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