Activate the virtual keyboard.
[platform/upstream/libwlmessage.git] / libwlmessage.c
1 /* Copyright © 2014 Manuel Bachmann */
2
3 #include <linux/input.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <glib.h>
7
8 #include "window.h"
9 #include "text-client-protocol.h"
10 #include "libwlmessage.h"
11 #define MAX_LINES 6
12
13
14 struct message_window {
15         struct window *window;
16         struct widget *widget;
17         cairo_surface_t *surface;
18
19         char *message;
20         char *title;
21         int frame_type; /* for titlebuttons */
22         int resizable;
23
24         cairo_surface_t *icon;
25         struct entry *entry;
26         int buttons_nb;
27         struct wl_list button_list;
28
29         struct wlmessage *wlmessage;
30 };
31
32 struct button {
33         struct widget *widget;
34         int focused, pressed;
35         struct wl_list link;
36
37         char *caption;
38         int value;
39
40         struct message_window *message_window;
41 };
42
43 struct entry {
44         struct widget *widget;
45         int active;
46
47         struct wl_text_input *text_input;
48         char *text;
49         int cursor_pos;
50         int cursor_anchor;
51         int last_vkb_len;
52
53         struct message_window *message_window;
54 };
55
56 struct wlmessage {
57         struct message_window *message_window;
58         struct wl_text_input_manager *text_input_manager;
59         int default_value;
60         int timeout;
61 };
62
63  /* ---------------------------------------- */
64
65  /* -- HELPER FUNCTIONS -- */
66
67 int
68 get_number_of_lines (char *text)
69 {
70         int lines_num = 0;
71
72         gchar **lines = g_strsplit (text, "\n", -1);
73
74         while ((lines[lines_num] != NULL) && (lines_num < MAX_LINES))
75                 lines_num++;
76
77         g_strfreev (lines);
78
79         return lines_num;
80 }
81
82 int
83 get_max_length_of_lines (char *text)
84 {
85         int lines_num = 0;
86         int length = 0;
87
88         gchar **lines = g_strsplit (text, "\n", -1);
89
90         while ((lines[lines_num] != NULL) && (lines_num < MAX_LINES)) {
91                 if (strlen (lines[lines_num]) > length)
92                         length = strlen (lines[lines_num]);
93                 lines_num++;
94         }
95
96         g_strfreev (lines);
97
98         return length;
99 }
100
101 char **
102 get_lines (char *text)
103 {
104         gchar **lines = g_strsplit (text, "\n", -1);
105
106         return lines;
107 }
108
109  /* ---------------------------------------- */
110
111  /* -- VIRTUAL KEYBOARD FUNCTIONS -- */
112
113 static void
114 text_input_enter(void *data,
115                  struct wl_text_input *text_input,
116                  struct wl_surface *surface)
117 {
118 }
119
120 static void
121 text_input_leave(void *data,
122                  struct wl_text_input *text_input)
123 {
124 }
125
126 static void
127 text_input_modifiers_map(void *data,
128                          struct wl_text_input *text_input,
129                          struct wl_array *map)
130 {
131 }
132
133 static void
134 text_input_input_panel_state(void *data,
135                              struct wl_text_input *text_input,
136                              uint32_t state)
137 {
138 }
139
140 static void
141 text_input_preedit_string(void *data,
142                           struct wl_text_input *text_input,
143                           uint32_t serial,
144                           const char *text,
145                           const char *commit)
146 {
147         struct entry *entry = data;
148         char *new_text;
149
150         if (strlen(entry->text) >= 18)
151                 return;
152
153          /* workaround to prevent using Backspace for now */
154         if (strlen(text) < entry->last_vkb_len) {
155                 entry->last_vkb_len = strlen(text);
156                 return;
157         } else {
158                 entry->last_vkb_len = strlen(text);
159         }
160
161         new_text = malloc (strlen(entry->text) + 1 + 1);
162         strncpy (new_text, entry->text, entry->cursor_pos);
163         strcpy (new_text+entry->cursor_pos, text+(strlen(text)-1));
164         strcpy (new_text+entry->cursor_pos+1, entry->text+entry->cursor_pos);
165         free (entry->text);
166         entry->text = new_text;
167         entry->cursor_pos++;
168
169         widget_schedule_redraw (entry->widget);
170 }
171
172 static void
173 text_input_preedit_styling(void *data,
174                            struct wl_text_input *text_input,
175                            uint32_t index,
176                            uint32_t length,
177                            uint32_t style)
178 {
179 }
180
181 static void
182 text_input_preedit_cursor(void *data,
183                           struct wl_text_input *text_input,
184                           int32_t index)
185 {
186 }
187
188 static void
189 text_input_commit_string(void *data,
190                          struct wl_text_input *text_input,
191                          uint32_t serial,
192                          const char *text)
193 {
194 }
195
196 static void
197 text_input_cursor_position(void *data,
198                            struct wl_text_input *text_input,
199                            int32_t index,
200                            int32_t anchor)
201 {
202 }
203
204 static void
205 text_input_keysym(void *data,
206                   struct wl_text_input *text_input,
207                   uint32_t serial,
208                   uint32_t time,
209                   uint32_t sym,
210                   uint32_t state,
211                   uint32_t modifiers)
212 {
213         struct entry *entry = data;
214         char *new_text;
215
216         if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
217                 return;
218
219          /* use Tab as Backspace until I figure this out */
220         if (sym == XKB_KEY_Tab) {
221                 if (entry->cursor_pos != 0) {
222                         new_text = malloc (strlen(entry->text));
223                         strncpy (new_text, entry->text, entry->cursor_pos - 1);
224                         strcpy (new_text+entry->cursor_pos-1, entry->text+entry->cursor_pos);
225                         free (entry->text);
226                         entry->text = new_text;
227                         entry->cursor_pos--;
228                 }
229         }       
230
231         if (sym == XKB_KEY_Left) {
232                 if (entry->cursor_pos != 0)
233                         entry->cursor_pos--;
234         }
235
236         if (sym == XKB_KEY_Right) {
237                 if (entry->cursor_pos != strlen (entry->text))
238                         entry->cursor_pos++;
239         }
240
241         if (sym == XKB_KEY_Return) {
242                 //fprintf (stdout, entry->text);
243                 wlmessage_destroy (entry->message_window->wlmessage);
244                 exit (entry->message_window->wlmessage->default_value);
245         }
246
247         widget_schedule_redraw (entry->widget);
248 }
249
250 static void
251 text_input_language(void *data,
252                     struct wl_text_input *text_input,
253                     uint32_t serial,
254                     const char *language)
255 {
256 }
257
258 static void
259 text_input_text_direction(void *data,
260                           struct wl_text_input *text_input,
261                           uint32_t serial,
262                           uint32_t direction)
263 {
264 }
265
266 static const struct wl_text_input_listener text_input_listener = {
267         text_input_enter,
268         text_input_leave,
269         text_input_modifiers_map,
270         text_input_input_panel_state,
271         text_input_preedit_string,
272         text_input_preedit_styling,
273         text_input_preedit_cursor,
274         text_input_commit_string,
275         text_input_cursor_position,
276         NULL,
277         text_input_keysym,
278         text_input_language,
279         text_input_text_direction
280 };
281
282  /* ---------------------------------------- */
283
284  /* -- HANDLERS -- */
285
286
287 static void
288 entry_click_handler(struct widget *widget,
289                 struct input *input, uint32_t time,
290                 uint32_t button,
291                 enum wl_pointer_button_state state, void *data)
292 {
293         struct entry *entry = data;
294
295         widget_schedule_redraw (widget);
296
297         if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
298                 if (!entry->text_input) {
299                         entry->text_input = wl_text_input_manager_create_text_input (entry->message_window->wlmessage->text_input_manager);
300                         wl_text_input_add_listener (entry->text_input, &text_input_listener, entry);
301                 }
302
303                 struct wl_seat *seat = input_get_seat (input);
304                 struct wl_surface *surface = window_get_wl_surface (entry->message_window->window);
305                 wl_text_input_show_input_panel (entry->text_input);
306                 wl_text_input_activate (entry->text_input, seat, surface);
307
308                 entry->active = 1;
309         }
310 }
311
312 static void
313 entry_touch_handler(struct widget *widget, struct input *input,
314                  uint32_t serial, uint32_t time, int32_t id,
315                  float tx, float ty, void *data)
316 {
317         struct entry *entry = data;
318
319         widget_schedule_redraw (widget);
320
321         if (!entry->text_input) {
322                 entry->text_input = wl_text_input_manager_create_text_input (entry->message_window->wlmessage->text_input_manager);
323                 wl_text_input_add_listener (entry->text_input, &text_input_listener, entry);
324         }
325
326         struct wl_seat *seat = input_get_seat (input);
327         struct wl_surface *surface = window_get_wl_surface (entry->message_window->window);
328         wl_text_input_show_input_panel (entry->text_input);
329         wl_text_input_activate (entry->text_input, seat, surface);
330
331         entry->active = 1;
332 }
333
334 static int
335 entry_motion_handler(struct widget *widget,
336                 struct input *input, uint32_t time,
337                 float x, float y, void *data)
338 {
339         return CURSOR_IBEAM;
340 }
341
342 static void
343 entry_redraw_handler (struct widget *widget, void *data)
344 {
345         struct entry *entry = data;
346         struct rectangle allocation;
347         cairo_t *cr;
348         cairo_text_extents_t extents;
349         cairo_text_extents_t leftp_extents;
350         char *leftp_text;
351         int char_pos;
352
353         widget_get_allocation (widget, &allocation);
354
355         cr = widget_cairo_create (entry->message_window->widget);
356         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
357         cairo_rectangle (cr,
358                         allocation.x,
359                         allocation.y,
360                         allocation.width,
361                         allocation.height);
362         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
363         cairo_fill (cr);
364         cairo_set_line_width (cr, 1);
365         cairo_rectangle (cr,
366                         allocation.x,
367                         allocation.y,
368                         allocation.width,
369                         allocation.height);
370         if (entry->active)
371                 cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
372         else
373                 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
374         cairo_stroke_preserve(cr);
375
376         cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
377         cairo_select_font_face (cr, "sans",
378                                 CAIRO_FONT_SLANT_NORMAL,
379                                 CAIRO_FONT_WEIGHT_NORMAL);
380         cairo_set_font_size (cr, 14);
381         cairo_text_extents (cr, entry->text, &extents);
382                         char_pos = strlen(entry->text) -1;                                              /* for spaces at the end */
383                         while (char_pos >= 0 && entry->text[char_pos] == ' ') {
384                                 extents.width += 5.0;
385                                 char_pos--;
386                         }
387         cairo_move_to (cr, allocation.x + (allocation.width - extents.width)/2,
388                            allocation.y + (allocation.height - extents.height)/2 + 10);
389         cairo_show_text (cr, entry->text);
390
391         if (entry->active) {
392                 leftp_text = malloc (entry->cursor_pos + 1);
393                 strncpy (leftp_text, entry->text, entry->cursor_pos);
394                 leftp_text[entry->cursor_pos] = '\0';
395                 cairo_text_extents (cr, leftp_text, &leftp_extents);
396                         char_pos = strlen(leftp_text) -1;
397                         while (char_pos >= 0 && leftp_text[char_pos] == ' ') {
398                                 leftp_extents.width += 5.0;
399                                 char_pos--;
400                         }
401                 free (leftp_text);
402
403                 cairo_move_to (cr, allocation.x + (allocation.width - extents.width)/2 + leftp_extents.width,
404                                    allocation.y + (allocation.height - extents.height)/2 + 15);
405                 cairo_line_to(cr, allocation.x + (allocation.width - extents.width)/2 + leftp_extents.width,
406                                    allocation.y + (allocation.height - extents.height)/2 - 5);
407                 cairo_stroke(cr);
408         }
409
410         cairo_destroy (cr);
411 }
412
413 void
414 button_send_activate (struct button *button, int value)
415 {
416         if (button->message_window->entry)
417                 fprintf (stdout, button->message_window->entry->text);
418         wlmessage_destroy (button->message_window->wlmessage);
419         exit (value);
420 }
421
422 static void
423 button_click_handler(struct widget *widget,
424                 struct input *input, uint32_t time,
425                 uint32_t butt,
426                 enum wl_pointer_button_state state, void *data)
427 {
428         struct button *button = data;
429
430         widget_schedule_redraw (widget);
431
432         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
433                 button->pressed = 1;
434         } else {
435                 button->pressed = 0;
436                 button_send_activate (button, button->value);
437         }
438 }
439
440 static void
441 button_touch_down_handler(struct widget *widget, struct input *input,
442                  uint32_t serial, uint32_t time, int32_t id,
443                  float tx, float ty, void *data)
444 {
445         struct button *button = data;
446
447         button->focused = 1;
448         widget_schedule_redraw (widget);
449 }
450
451 static void
452 button_touch_up_handler(struct widget *widget, struct input *input,
453                  uint32_t serial, uint32_t time, int32_t id,
454                  void *data)
455 {
456         struct button *button = data;
457
458         button->focused = 0;
459         widget_schedule_redraw (widget);
460
461         button_send_activate (button, button->value);
462 }
463
464 static int
465 button_enter_handler(struct widget *widget, struct input *input,
466                              float x, float y, void *data)
467 {
468         struct button *button = data;
469
470         button->focused = 1;
471         widget_schedule_redraw (widget);
472
473         return CURSOR_LEFT_PTR;
474 }
475
476 static void
477 button_leave_handler(struct widget *widget,
478                              struct input *input, void *data)
479 {
480         struct button *button = data;
481
482         button->focused = 0;
483         widget_schedule_redraw (widget);
484 }
485
486 static void
487 button_redraw_handler (struct widget *widget, void *data)
488 {
489         struct button *button = data;
490         struct rectangle allocation;
491         cairo_t *cr;
492         cairo_text_extents_t extents;
493
494         widget_get_allocation (widget, &allocation);
495         if (button->pressed) {
496                 allocation.x++;
497                 allocation.y++;
498         }
499
500         cr = widget_cairo_create (button->message_window->widget);
501         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
502         cairo_rectangle (cr,
503                         allocation.x,
504                         allocation.y,
505                         allocation.width,
506                         allocation.height);
507         if (button->focused)
508                 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
509         else
510                 cairo_set_source_rgb (cr, 0.9, 0.9, 0.9);
511         cairo_fill (cr);
512         cairo_set_line_width (cr, 1);
513         cairo_rectangle (cr,
514                         allocation.x,
515                         allocation.y,
516                         allocation.width,
517                         allocation.height);
518         cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
519         cairo_stroke_preserve(cr);
520         cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
521         cairo_set_font_size (cr, 14);
522         cairo_text_extents (cr, button->caption, &extents);
523         cairo_move_to (cr, allocation.x + (allocation.width - extents.width)/2,
524                            allocation.y + (allocation.height - extents.height)/2 + 10);
525         cairo_show_text (cr, button->caption);
526         cairo_destroy (cr);
527 }
528
529 static void
530 key_handler (struct window *window, struct input *input, uint32_t time,
531                  uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
532                  void *data)
533 {
534         struct message_window *message_window = data;
535         struct entry *entry = message_window->entry;
536         char *new_text;
537         char text[16];
538
539         if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
540                 return;
541
542         if (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter) {
543 #if 0
544                 if (entry)
545                         fprintf (stdout, entry->text);
546 #endif
547                 wlmessage_destroy (message_window->wlmessage);
548                 exit (message_window->wlmessage->default_value);
549         }
550
551         if (entry && entry->active) {
552                 switch (sym) {
553                         case XKB_KEY_BackSpace:
554                                 if (entry->cursor_pos == 0)
555                                         break;
556                                 new_text = malloc (strlen(entry->text));
557                                 strncpy (new_text, entry->text, entry->cursor_pos - 1);
558                                 strcpy (new_text+entry->cursor_pos-1, entry->text+entry->cursor_pos);
559                                 free (entry->text);
560                                 entry->text = new_text;
561                                 entry->cursor_pos--;
562                                 break;
563                         case XKB_KEY_Delete:
564                                 if (entry->cursor_pos == strlen (entry->text))
565                                         break;
566                                 new_text = malloc (strlen(entry->text));
567                                 strncpy (new_text, entry->text, entry->cursor_pos);
568                                 strcpy (new_text+entry->cursor_pos, entry->text+entry->cursor_pos+1);
569                                 free (entry->text);
570                                 entry->text = new_text;
571                                 break;
572                         case XKB_KEY_Left:
573                                 if (entry->cursor_pos != 0)
574                                         entry->cursor_pos--;
575                                 break;
576                         case XKB_KEY_Right:
577                                 if (entry->cursor_pos != strlen (entry->text))
578                                         entry->cursor_pos++;
579                                 break;
580                         case XKB_KEY_Tab:
581                                 break;
582                         default:
583                                 if (strlen(entry->text) >= 18)
584                                         break;
585                                 if (xkb_keysym_to_utf8 (sym, text, sizeof(text)) <= 0)
586                                         break;
587                                 if (strlen(text) > 1)   /* dismiss non-ASCII characters for now */
588                                         break;
589                                 new_text = malloc (strlen(entry->text) + strlen(text) + 1);
590                                 strncpy (new_text, entry->text, entry->cursor_pos);
591                                 strcpy (new_text+entry->cursor_pos, text);
592                                 strcpy (new_text+entry->cursor_pos+strlen(text), entry->text+entry->cursor_pos);
593                                 free (entry->text);
594                                 entry->text = new_text;
595                                 entry->cursor_pos++;
596                 }
597                 widget_schedule_redraw(entry->widget);
598         }
599 }
600
601 static void
602 resize_handler (struct widget *widget, int32_t width, int32_t height, void *data)
603 {
604         struct message_window *message_window = data;
605         struct entry *entry;
606         struct button *button;
607         struct rectangle allocation;
608         int buttons_width, extended_width;
609         int x;
610
611         widget_get_allocation (widget, &allocation);
612
613         x = allocation.x + (width - 240)/2;
614
615         if (message_window->entry) {
616                 entry = message_window->entry;
617                 widget_set_allocation (entry->widget, x, allocation.y + height - 16*2 - 32*2,
618                                                       240, 32);
619         }
620
621         buttons_width = 0;
622         wl_list_for_each (button, &message_window->button_list, link) {
623                 extended_width = strlen(button->caption) - 5;
624                 if (extended_width < 0) extended_width = 0;
625                 buttons_width += 60 + extended_width*10;
626         }
627
628         x = allocation.x + (width - buttons_width)/2
629                          - (message_window->buttons_nb-1)*10;
630
631         wl_list_for_each (button, &message_window->button_list, link) {
632                 extended_width = strlen(button->caption) - 5;
633                 if (extended_width < 0) extended_width = 0;
634                 widget_set_allocation (button->widget, x, allocation.y + height - 16 - 32,
635                                                        60 + extended_width*10, 32); 
636                 x += 60 + extended_width*10 + 10;
637         }
638 }
639
640 static void
641 redraw_handler (struct widget *widget, void *data)
642 {
643         struct message_window *message_window = data;
644         struct rectangle allocation;
645         cairo_surface_t *surface;
646         cairo_t *cr;
647         cairo_text_extents_t extents;
648         int lines_nb;
649         char **lines;
650
651         widget_get_allocation (message_window->widget, &allocation);
652
653         surface = window_get_surface (message_window->window);
654         cr = cairo_create (surface);
655         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
656         cairo_rectangle (cr,
657                         allocation.x,
658                         allocation.y,
659                         allocation.width,
660                         allocation.height);
661         cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 1.0);
662         cairo_fill (cr);
663
664         if (message_window->icon) {
665                         cairo_set_source_surface (cr, message_window->icon,
666                                                       allocation.x + (allocation.width - 64.0)/2,
667                                                       allocation.y + 10);
668                         cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
669                         cairo_paint (cr);
670                         cairo_set_source_surface (cr, surface, 0.0, 0.0);
671         }
672
673         cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
674         cairo_select_font_face (cr, "sans",
675                                 CAIRO_FONT_SLANT_NORMAL,
676                                 CAIRO_FONT_WEIGHT_NORMAL);
677         cairo_set_font_size (cr, 18);
678
679         lines_nb = get_number_of_lines (message_window->message);
680         lines = get_lines (message_window->message);
681
682         int i;
683         for (i = 0; i < lines_nb; i++) {
684                 cairo_text_extents (cr, lines[i], &extents);
685                 cairo_move_to (cr, allocation.x + (allocation.width - extents.width)/2,
686                                    allocation.y + (allocation.height - lines_nb * extents.height)/2
687                                                 + i*(extents.height+10)
688                                                 + (!message_window->icon ? 0 : 32)
689                                                 - (!message_window->entry ? 0 : 32)
690                                                 - (!message_window->buttons_nb ? 0 : 32));
691                 cairo_show_text (cr, lines[i]);
692         }
693
694         g_strfreev (lines);
695
696         cairo_destroy (cr);
697 }
698
699 static void
700 global_handler(struct display *display, uint32_t name,
701                const char *interface, uint32_t version, void *data)
702 {
703         struct wlmessage *wlmessage = data;
704
705         if (!strcmp(interface, "wl_text_input_manager")) {
706                 wlmessage->text_input_manager = display_bind (display, name,
707                                                               &wl_text_input_manager_interface, 1);
708         }
709 }
710
711  /* ---------------------------------------- */
712
713 void
714 wlmessage_set_title (struct wlmessage *wlmessage, char *title)
715 {
716         if ((!wlmessage) || (!title))
717                 return;
718
719         struct message_window *message_window = wlmessage->message_window;
720
721         if (message_window->title)
722                 free (message_window->title);
723
724         message_window->title = strdup (title);
725 }
726
727 char *
728 wlmessage_get_title (struct wlmessage *wlmessage)
729 {
730         if (!wlmessage)
731                 return NULL;
732
733         struct message_window *message_window = wlmessage->message_window;
734
735         return message_window->title;
736 }
737
738 void
739 wlmessage_set_titlebuttons (struct wlmessage *wlmessage, enum wlmessage_titlebutton titlebuttons)
740 {
741         if (!wlmessage)
742                 return;
743
744         struct message_window *message_window = wlmessage->message_window;
745
746         message_window->frame_type = FRAME_NONE;
747         
748         if (titlebuttons && WLMESSAGE_TITLEBUTTON_MINIMIZE)
749                 message_window->frame_type = message_window->frame_type | FRAME_MINIMIZE;
750         if (titlebuttons && WLMESSAGE_TITLEBUTTON_MAXIMIZE)
751                 message_window->frame_type = message_window->frame_type | FRAME_MAXIMIZE;
752         if (titlebuttons && WLMESSAGE_TITLEBUTTON_CLOSE)
753                 message_window->frame_type = message_window->frame_type | FRAME_CLOSE;
754 }
755
756 enum wlmessage_titlebutton
757 wlmessage_get_titlebuttons (struct wlmessage *wlmessage)
758 {
759         if (!wlmessage)
760                 return 0;
761
762         struct message_window *message_window = wlmessage->message_window;
763         enum wlmessage_titlebutton titlebuttons;
764
765         titlebuttons = WLMESSAGE_TITLEBUTTON_NONE;
766
767         if (message_window->frame_type && FRAME_MINIMIZE)
768                 titlebuttons = titlebuttons | WLMESSAGE_TITLEBUTTON_MINIMIZE;
769         if (message_window->frame_type && FRAME_MAXIMIZE)
770                 titlebuttons = titlebuttons | WLMESSAGE_TITLEBUTTON_MAXIMIZE;
771         if (message_window->frame_type && FRAME_CLOSE)
772                 titlebuttons = titlebuttons | WLMESSAGE_TITLEBUTTON_CLOSE;
773
774         return titlebuttons;
775 }
776
777 void
778 wlmessage_set_noresize (struct wlmessage *wlmessage, unsigned int not_resizable)
779 {
780         if (!wlmessage)
781                 return;
782
783         struct message_window *message_window = wlmessage->message_window;
784
785         message_window->resizable = !not_resizable;
786 }
787
788 unsigned
789 wlmessage_get_noresize (struct wlmessage *wlmessage)
790 {
791         if (!wlmessage)
792                 return;
793
794         struct message_window *message_window = wlmessage->message_window;
795
796         return !message_window->resizable;
797 }
798
799 void
800 wlmessage_set_icon (struct wlmessage *wlmessage, char *icon_path)
801 {
802         if ((!wlmessage) || (!icon_path))
803                 return;
804
805         struct message_window *message_window = wlmessage->message_window;
806         cairo_surface_t *icon;
807         cairo_status_t status;
808
809         icon = cairo_image_surface_create_from_png (icon_path);
810         status = cairo_surface_status (icon);
811
812         if (status == CAIRO_STATUS_SUCCESS) {
813                         message_window->icon = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 64, 64);
814                         cairo_t *icon_cr = cairo_create (message_window->icon);
815                          /* rescale to 64x64 */
816                         int width = cairo_image_surface_get_width (icon);
817                         int height = cairo_image_surface_get_height (icon);
818                         if (width != height != 64) {
819                                 double ratio = ((64.0/width) < (64.0/height) ? (64.0/width) : (64.0/height));
820                                 cairo_scale (icon_cr, ratio, ratio);
821                         }
822                         cairo_set_source_surface (icon_cr, icon, 0.0, 0.0);
823                         cairo_paint (icon_cr);
824                         cairo_destroy (icon_cr);
825                         cairo_surface_destroy (icon);
826         }
827
828 }
829
830 void
831 wlmessage_set_message (struct wlmessage *wlmessage, char *message)
832 {
833         if ((!wlmessage) || (!message))
834                 return;
835
836         struct message_window *message_window = wlmessage->message_window;
837
838         if (message_window->message)
839                 free (message_window->message);
840
841         message_window->message = strdup (message);
842 }
843
844 char *
845 wlmessage_get_message (struct wlmessage *wlmessage)
846 {
847         if (!wlmessage)
848                 return NULL;
849
850         struct message_window *message_window = wlmessage->message_window;
851
852         return message_window->message;
853 }
854
855 void
856 wlmessage_set_message_file (struct wlmessage *wlmessage, char *file_path)
857 {
858         if ((!wlmessage) || (!file_path))
859                 return;
860
861         struct message_window *message_window = wlmessage->message_window;
862         FILE *file = NULL;
863         char *text = NULL;
864         int i, c;
865
866         file = fopen (file_path, "r");
867         if (!file) {
868                 return;
869         } else {
870                 i = 0;
871                 text = malloc (sizeof(char));
872                 while (c != EOF) {
873                         c = fgetc (file);
874                         if (c != EOF) {
875                                 realloc (text, (i+1)*sizeof(char));
876                                 text[i] = c;
877                                 i++;
878                         }
879                 }
880                 realloc (text, (i+1)*sizeof(char));
881                 text[i] = '\0';
882                 fclose (file);
883         }
884
885         if (message_window->message)
886                 free (message_window->message);
887
888         message_window->message = text;
889 }
890
891 void
892 wlmessage_add_button (struct wlmessage *wlmessage, int index, char *caption)
893 {
894         if ((!wlmessage) || (!caption))
895                 return;
896
897         struct message_window *message_window = wlmessage->message_window;
898         struct button *button;
899
900         button = xzalloc (sizeof *button);
901         button->caption = strdup (caption);
902         button->value = index;
903         button->message_window = message_window;
904
905         message_window->buttons_nb++;
906         wl_list_insert (message_window->button_list.prev, &button->link);
907 }
908
909 void
910 wlmessage_delete_button (struct wlmessage *wlmessage, int index)
911 {
912         if (!wlmessage)
913                 return;
914
915         struct message_window *message_window = wlmessage->message_window;
916
917         struct button *button, *tmp;
918         wl_list_for_each_safe (button, tmp, &message_window->button_list, link) {
919                 if (button->value == index) {
920                         wl_list_remove (&button->link);
921                         widget_destroy (button->widget);
922                         free (button->caption);
923                         free (button);
924                         message_window->buttons_nb--;
925                 }
926         }
927 }
928
929 void
930 wlmessage_set_default_button (struct wlmessage *wlmessage, int index)
931 {
932         if (!wlmessage)
933                 return;
934
935         struct message_window *message_window = wlmessage->message_window;
936         struct button *button;
937
938         wl_list_for_each (button, &message_window->button_list, link) {
939                 if (button->value == index)
940                                 wlmessage->default_value = button->value;
941         }
942 }
943
944 void
945 wlmessage_set_textfield (struct wlmessage *wlmessage, char *default_text)
946 {
947         if ((!wlmessage) || (!default_text))
948                 return;
949
950         struct message_window *message_window = wlmessage->message_window;
951         struct entry *entry;
952
953         entry = xzalloc (sizeof *entry);
954         entry->text = strdup (default_text);
955         entry->cursor_pos = strlen (entry->text);
956         entry->cursor_anchor = entry->cursor_pos;
957         entry->last_vkb_len = 0;
958         entry->active = 0;
959         entry->message_window = message_window;
960
961         message_window->entry = entry;
962 }
963
964 char *
965 wlmessage_get_textfield (struct wlmessage *wlmessage)
966 {
967         if (!wlmessage)
968                 return NULL;
969
970         struct message_window *message_window = wlmessage->message_window;
971
972         if (!message_window->entry)
973                 return NULL;
974         else
975                 return message_window->entry->text;
976 }
977
978 void
979 wlmessage_set_timeout (struct wlmessage *wlmessage, unsigned int timeout)
980 {
981         if (!wlmessage)
982                 return;
983
984         wlmessage->timeout = timeout;
985 }
986
987 unsigned int
988 wlmessage_get_timeout (struct wlmessage *wlmessage)
989 {
990         if (!wlmessage)
991                 return 0;
992
993         return wlmessage->timeout;
994 }
995
996 int
997 wlmessage_show (struct wlmessage *wlmessage, char **input_text)
998 {
999         if (!wlmessage)
1000                 return 0;
1001
1002         struct message_window *message_window = wlmessage->message_window;
1003         struct display *display = NULL;
1004         struct entry *entry;
1005         struct button *button;
1006         int extended_width = 0;
1007         int lines_nb = 0;
1008
1009         display = display_create (NULL, NULL);
1010         if (!display) {
1011                 fprintf (stderr, "Failed to connect to a Wayland compositor !\n");
1012                 return -1;      // HUH ?
1013         }
1014
1015         if (wlmessage->timeout)
1016                 display_set_timeout (display, wlmessage->timeout);
1017
1018         message_window->window = window_create (display);
1019         message_window->widget = window_frame_create (message_window->window,
1020                                                       message_window->frame_type,
1021                                                       message_window->resizable, message_window);
1022         window_set_title (message_window->window, message_window->title);
1023
1024          /* add entry */
1025         if (message_window->entry) {
1026                 entry = message_window->entry;
1027                 entry->widget = widget_add_widget (message_window->widget, entry);
1028                 widget_set_redraw_handler (entry->widget, entry_redraw_handler);
1029                 widget_set_motion_handler (entry->widget, entry_motion_handler);
1030                 widget_set_button_handler (entry->widget, entry_click_handler);
1031                 widget_set_touch_down_handler (entry->widget, entry_touch_handler);
1032         }
1033
1034          /* add buttons */
1035         wl_list_for_each (button, &message_window->button_list, link) {
1036                 button->widget = widget_add_widget (message_window->widget, button);
1037                 widget_set_redraw_handler (button->widget, button_redraw_handler);
1038                 widget_set_enter_handler (button->widget, button_enter_handler);
1039                 widget_set_leave_handler (button->widget, button_leave_handler);
1040                 widget_set_button_handler (button->widget, button_click_handler);
1041                 widget_set_touch_down_handler (button->widget, button_touch_down_handler);
1042                 widget_set_touch_up_handler (button->widget, button_touch_up_handler);
1043         }
1044
1045         extended_width = (get_max_length_of_lines (message_window->message)) - 35;
1046          if (extended_width < 0) extended_width = 0;
1047         lines_nb = get_number_of_lines (message_window->message);
1048
1049         window_set_user_data (message_window->window, message_window);
1050         window_set_key_handler (message_window->window, key_handler);
1051         widget_set_redraw_handler (message_window->widget, redraw_handler);
1052         widget_set_resize_handler (message_window->widget, resize_handler);
1053
1054         window_schedule_resize (message_window->window,
1055                                 480 + extended_width*10,
1056                                 280 + lines_nb*16 + (!message_window->entry ? 0 : 1)*32
1057                                                   + (!message_window->buttons_nb ? 0 : 1)*32);
1058
1059         display_set_user_data (display, wlmessage);
1060         display_set_global_handler (display, global_handler);
1061         display_run (display);
1062
1063         return 0;
1064 }
1065
1066 struct wlmessage *
1067 wlmessage_create ()
1068 {
1069         struct wlmessage *wlmessage;
1070
1071         wlmessage = xzalloc (sizeof *wlmessage);
1072         wlmessage->default_value = 0;
1073         wlmessage->timeout = 0;
1074
1075         wlmessage->message_window = xzalloc (sizeof *wlmessage->message_window);
1076         wlmessage->message_window->title = strdup ("wlmessage");
1077         wlmessage->message_window->frame_type = FRAME_ALL;
1078         wlmessage->message_window->resizable = 1;
1079         wlmessage->message_window->icon = NULL;
1080         wlmessage->message_window->message = NULL;
1081         wlmessage->message_window->entry = NULL;
1082         wlmessage->message_window->buttons_nb = 0;
1083         wl_list_init (&wlmessage->message_window->button_list);
1084         wlmessage->message_window->wlmessage = wlmessage;
1085
1086         return wlmessage;
1087 }
1088
1089 void
1090 wlmessage_destroy (struct wlmessage *wlmessage)
1091 {
1092         if (!wlmessage)
1093                 return;
1094
1095         struct message_window *message_window = wlmessage->message_window;
1096
1097         if (message_window->surface)
1098                 cairo_surface_destroy (message_window->surface);
1099         if (message_window->icon)
1100                 cairo_surface_destroy (message_window->icon);
1101         widget_destroy (message_window->widget);
1102         window_destroy (message_window->window);
1103         free (message_window->title);
1104         free (message_window->message);
1105         free (message_window);
1106
1107         free (wlmessage);
1108 }
1109
1110  /* ---------------------------------------- */
1111