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