button-test: Use wl_display_roundtrip instead of yield()
[profile/ivi/weston.git] / clients / desktop-shell.c
1 /*
2  * Copyright © 2011 Kristian Høgsberg
3  * Copyright © 2011 Collabora, Ltd.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <math.h>
31 #include <cairo.h>
32 #include <sys/wait.h>
33 #include <sys/timerfd.h>
34 #include <sys/epoll.h> 
35 #include <linux/input.h>
36 #include <libgen.h>
37 #include <ctype.h>
38 #include <time.h>
39
40 #include <wayland-client.h>
41 #include "window.h"
42 #include "../shared/cairo-util.h"
43 #include "../shared/config-parser.h"
44
45 #include "desktop-shell-client-protocol.h"
46
47 extern char **environ; /* defined by libc */
48
49 struct desktop {
50         struct display *display;
51         struct desktop_shell *shell;
52         struct unlock_dialog *unlock_dialog;
53         struct task unlock_task;
54         struct wl_list outputs;
55
56         struct window *grab_window;
57         struct widget *grab_widget;
58
59         enum cursor_type grab_cursor;
60 };
61
62 struct surface {
63         void (*configure)(void *data,
64                           struct desktop_shell *desktop_shell,
65                           uint32_t edges, struct window *window,
66                           int32_t width, int32_t height);
67 };
68
69 struct panel {
70         struct surface base;
71         struct window *window;
72         struct widget *widget;
73         struct wl_list launcher_list;
74         struct panel_clock *clock;
75 };
76
77 struct background {
78         struct surface base;
79         struct window *window;
80         struct widget *widget;
81 };
82
83 struct output {
84         struct wl_output *output;
85         struct wl_list link;
86
87         struct panel *panel;
88         struct background *background;
89 };
90
91 struct panel_launcher {
92         struct widget *widget;
93         struct panel *panel;
94         cairo_surface_t *icon;
95         int focused, pressed;
96         char *path;
97         struct wl_list link;
98         struct wl_array envp;
99         struct wl_array argv;
100 };
101
102 struct panel_clock {
103         struct widget *widget;
104         struct panel *panel;
105         struct task clock_task;
106         int clock_fd;
107 };
108
109 struct unlock_dialog {
110         struct window *window;
111         struct widget *widget;
112         struct widget *button;
113         int button_focused;
114         int closing;
115         struct desktop *desktop;
116 };
117
118 static char *key_background_image = DATADIR "/weston/pattern.png";
119 static char *key_background_type = "tile";
120 static uint32_t key_panel_color = 0xaa000000;
121 static uint32_t key_background_color = 0xff002244;
122 static char *key_launcher_icon;
123 static char *key_launcher_path;
124 static void launcher_section_done(void *data);
125 static int key_locking = 1;
126
127 static const struct config_key shell_config_keys[] = {
128         { "background-image", CONFIG_KEY_STRING, &key_background_image },
129         { "background-type", CONFIG_KEY_STRING, &key_background_type },
130         { "panel-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_panel_color },
131         { "background-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_background_color },
132         { "locking", CONFIG_KEY_BOOLEAN, &key_locking },
133 };
134
135 static const struct config_key launcher_config_keys[] = {
136         { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
137         { "path", CONFIG_KEY_STRING, &key_launcher_path },
138 };
139
140 static const struct config_section config_sections[] = {
141         { "shell",
142           shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
143         { "launcher",
144           launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
145           launcher_section_done }
146 };
147
148 static void
149 sigchild_handler(int s)
150 {
151         int status;
152         pid_t pid;
153
154         while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
155                 fprintf(stderr, "child %d exited\n", pid);
156 }
157
158 static void
159 menu_func(struct window *window, int index, void *data)
160 {
161         printf("Selected index %d from a panel menu.\n", index);
162 }
163
164 static void
165 show_menu(struct panel *panel, struct input *input, uint32_t time)
166 {
167         int32_t x, y;
168         static const char *entries[] = {
169                 "Roy", "Pris", "Leon", "Zhora"
170         };
171
172         input_get_position(input, &x, &y);
173         window_show_menu(window_get_display(panel->window),
174                          input, time, panel->window,
175                          x - 10, y - 10, menu_func, entries, 4);
176 }
177
178 static void
179 panel_launcher_activate(struct panel_launcher *widget)
180 {
181         char **argv;
182         pid_t pid;
183
184         pid = fork();
185         if (pid < 0) {
186                 fprintf(stderr, "fork failed: %m\n");
187                 return;
188         }
189
190         if (pid)
191                 return;
192
193         argv = widget->argv.data;
194         if (execve(argv[0], argv, widget->envp.data) < 0) {
195                 fprintf(stderr, "execl '%s' failed: %m\n", argv[0]);
196                 exit(1);
197         }
198 }
199
200 static void
201 panel_launcher_redraw_handler(struct widget *widget, void *data)
202 {
203         struct panel_launcher *launcher = data;
204         cairo_surface_t *surface;
205         struct rectangle allocation;
206         cairo_t *cr;
207
208         surface = window_get_surface(launcher->panel->window);
209         cr = cairo_create(surface);
210
211         widget_get_allocation(widget, &allocation);
212         if (launcher->pressed) {
213                 allocation.x++;
214                 allocation.y++;
215         }
216
217         cairo_set_source_surface(cr, launcher->icon,
218                                  allocation.x, allocation.y);
219         cairo_paint(cr);
220
221         if (launcher->focused) {
222                 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
223                 cairo_mask_surface(cr, launcher->icon,
224                                    allocation.x, allocation.y);
225         }
226
227         cairo_destroy(cr);
228 }
229
230 static int
231 panel_launcher_motion_handler(struct widget *widget, struct input *input,
232                               uint32_t time, float x, float y, void *data)
233 {
234         struct panel_launcher *launcher = data;
235
236         widget_set_tooltip(widget, basename((char *)launcher->path), x, y);
237
238         return CURSOR_LEFT_PTR;
239 }
240
241 static void
242 set_hex_color(cairo_t *cr, uint32_t color)
243 {
244         cairo_set_source_rgba(cr, 
245                               ((color >> 16) & 0xff) / 255.0,
246                               ((color >>  8) & 0xff) / 255.0,
247                               ((color >>  0) & 0xff) / 255.0,
248                               ((color >> 24) & 0xff) / 255.0);
249 }
250
251 static void
252 panel_redraw_handler(struct widget *widget, void *data)
253 {
254         cairo_surface_t *surface;
255         cairo_t *cr;
256         struct panel *panel = data;
257
258         surface = window_get_surface(panel->window);
259         cr = cairo_create(surface);
260         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
261         set_hex_color(cr, key_panel_color);
262         cairo_paint(cr);
263
264         cairo_destroy(cr);
265         cairo_surface_destroy(surface);
266 }
267
268 static int
269 panel_launcher_enter_handler(struct widget *widget, struct input *input,
270                              float x, float y, void *data)
271 {
272         struct panel_launcher *launcher = data;
273
274         launcher->focused = 1;
275         widget_schedule_redraw(widget);
276
277         return CURSOR_LEFT_PTR;
278 }
279
280 static void
281 panel_launcher_leave_handler(struct widget *widget,
282                              struct input *input, void *data)
283 {
284         struct panel_launcher *launcher = data;
285
286         launcher->focused = 0;
287         widget_destroy_tooltip(widget);
288         widget_schedule_redraw(widget);
289 }
290
291 static void
292 panel_launcher_button_handler(struct widget *widget,
293                               struct input *input, uint32_t time,
294                               uint32_t button,
295                               enum wl_pointer_button_state state, void *data)
296 {
297         struct panel_launcher *launcher;
298
299         launcher = widget_get_user_data(widget);
300         widget_schedule_redraw(widget);
301         if (state == WL_POINTER_BUTTON_STATE_RELEASED)
302                 panel_launcher_activate(launcher);
303 }
304
305 static void
306 clock_func(struct task *task, uint32_t events)
307 {
308         struct panel_clock *clock =
309                 container_of(task, struct panel_clock, clock_task);
310         uint64_t exp;
311
312         if (read(clock->clock_fd, &exp, sizeof exp) != sizeof exp)
313                 abort();
314         widget_schedule_redraw(clock->widget);
315 }
316
317 static void
318 panel_clock_redraw_handler(struct widget *widget, void *data)
319 {
320         cairo_surface_t *surface;
321         struct panel_clock *clock = data;
322         cairo_t *cr;
323         struct rectangle allocation;
324         cairo_text_extents_t extents;
325         cairo_font_extents_t font_extents;
326         time_t rawtime;
327         struct tm * timeinfo;
328         char string[128];
329
330         time(&rawtime);
331         timeinfo = localtime(&rawtime);
332         strftime(string, sizeof string, "%a %b %d, %I:%M %p", timeinfo);
333
334         widget_get_allocation(widget, &allocation);
335         if (allocation.width == 0)
336                 return;
337
338         surface = window_get_surface(clock->panel->window);
339         cr = cairo_create(surface);
340         cairo_select_font_face(cr, "sans",
341                                CAIRO_FONT_SLANT_NORMAL,
342                                CAIRO_FONT_WEIGHT_NORMAL);
343         cairo_set_font_size(cr, 14);
344         cairo_text_extents(cr, string, &extents);
345         cairo_font_extents (cr, &font_extents);
346         cairo_move_to(cr, allocation.x + 5,
347                       allocation.y + 3 * (allocation.height >> 2) + 1);
348         cairo_set_source_rgb(cr, 0, 0, 0);
349         cairo_show_text(cr, string);
350         cairo_move_to(cr, allocation.x + 4,
351                       allocation.y + 3 * (allocation.height >> 2));
352         cairo_set_source_rgb(cr, 1, 1, 1);
353         cairo_show_text(cr, string);
354         cairo_destroy(cr);
355 }
356
357 static int
358 clock_timer_reset(struct panel_clock *clock)
359 {
360         struct itimerspec its;
361
362         its.it_interval.tv_sec = 60;
363         its.it_interval.tv_nsec = 0;
364         its.it_value.tv_sec = 60;
365         its.it_value.tv_nsec = 0;
366         if (timerfd_settime(clock->clock_fd, 0, &its, NULL) < 0) {
367                 fprintf(stderr, "could not set timerfd\n: %m");
368                 return -1;
369         }
370
371         return 0;
372 }
373
374 static void
375 panel_destroy_clock(struct panel_clock *clock)
376 {
377         widget_destroy(clock->widget);
378
379         close(clock->clock_fd);
380
381         free(clock);
382 }
383
384 static void
385 panel_add_clock(struct panel *panel)
386 {
387         struct panel_clock *clock;
388         int timerfd;
389
390         timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
391         if (timerfd < 0) {
392                 fprintf(stderr, "could not create timerfd\n: %m");
393                 return;
394         }
395
396         clock = malloc(sizeof *clock);
397         memset(clock, 0, sizeof *clock);
398         clock->panel = panel;
399         panel->clock = clock;
400         clock->clock_fd = timerfd;
401
402         clock->clock_task.run = clock_func;
403         display_watch_fd(window_get_display(panel->window), clock->clock_fd,
404                          EPOLLIN, &clock->clock_task);
405         clock_timer_reset(clock);
406
407         clock->widget = widget_add_widget(panel->widget, clock);
408         widget_set_redraw_handler(clock->widget, panel_clock_redraw_handler);
409 }
410
411 static void
412 panel_button_handler(struct widget *widget,
413                      struct input *input, uint32_t time,
414                      uint32_t button,
415                      enum wl_pointer_button_state state, void *data)
416 {
417         struct panel *panel = data;
418
419         if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED)
420                 show_menu(panel, input, time);
421 }
422
423 static void
424 panel_resize_handler(struct widget *widget,
425                      int32_t width, int32_t height, void *data)
426 {
427         struct panel_launcher *launcher;
428         struct panel *panel = data;
429         int x, y, w, h;
430         
431         x = 10;
432         y = 16;
433         wl_list_for_each(launcher, &panel->launcher_list, link) {
434                 w = cairo_image_surface_get_width(launcher->icon);
435                 h = cairo_image_surface_get_height(launcher->icon);
436                 widget_set_allocation(launcher->widget,
437                                       x, y - h / 2, w + 1, h + 1);
438                 x += w + 10;
439         }
440         h=20;
441         w=170;
442
443         if (panel->clock)
444                 widget_set_allocation(panel->clock->widget,
445                                       width - w - 8, y - h / 2, w + 1, h + 1);
446 }
447
448 static void
449 panel_configure(void *data,
450                 struct desktop_shell *desktop_shell,
451                 uint32_t edges, struct window *window,
452                 int32_t width, int32_t height)
453 {
454         struct surface *surface = window_get_user_data(window);
455         struct panel *panel = container_of(surface, struct panel, base);
456
457         window_schedule_resize(panel->window, width, 32);
458 }
459
460 static void
461 panel_destroy_launcher(struct panel_launcher *launcher)
462 {
463         wl_array_release(&launcher->argv);
464         wl_array_release(&launcher->envp);
465
466         free(launcher->path);
467
468         cairo_surface_destroy(launcher->icon);
469
470         widget_destroy(launcher->widget);
471         wl_list_remove(&launcher->link);
472
473         free(launcher);
474 }
475
476 static void
477 panel_destroy(struct panel *panel)
478 {
479         struct panel_launcher *tmp;
480         struct panel_launcher *launcher;
481
482         panel_destroy_clock(panel->clock);
483
484         wl_list_for_each_safe(launcher, tmp, &panel->launcher_list, link)
485                 panel_destroy_launcher(launcher);
486
487         widget_destroy(panel->widget);
488         window_destroy(panel->window);
489
490         free(panel);
491 }
492
493 static struct panel *
494 panel_create(struct display *display)
495 {
496         struct panel *panel;
497
498         panel = malloc(sizeof *panel);
499         memset(panel, 0, sizeof *panel);
500
501         panel->base.configure = panel_configure;
502         panel->window = window_create_custom(display);
503         panel->widget = window_add_widget(panel->window, panel);
504         wl_list_init(&panel->launcher_list);
505
506         window_set_title(panel->window, "panel");
507         window_set_user_data(panel->window, panel);
508
509         widget_set_redraw_handler(panel->widget, panel_redraw_handler);
510         widget_set_resize_handler(panel->widget, panel_resize_handler);
511         widget_set_button_handler(panel->widget, panel_button_handler);
512         
513         panel_add_clock(panel);
514
515         return panel;
516 }
517
518 static cairo_surface_t *
519 load_icon_or_fallback(const char *icon)
520 {
521         cairo_surface_t *surface = cairo_image_surface_create_from_png(icon);
522         cairo_t *cr;
523
524         if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS)
525                 return surface;
526
527         cairo_surface_destroy(surface);
528         fprintf(stderr, "ERROR loading icon from file '%s'\n", icon);
529
530         /* draw fallback icon */
531         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
532                                              20, 20);
533         cr = cairo_create(surface);
534
535         cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
536         cairo_paint(cr);
537
538         cairo_set_source_rgba(cr, 0, 0, 0, 1);
539         cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
540         cairo_rectangle(cr, 0, 0, 20, 20);
541         cairo_move_to(cr, 4, 4);
542         cairo_line_to(cr, 16, 16);
543         cairo_move_to(cr, 4, 16);
544         cairo_line_to(cr, 16, 4);
545         cairo_stroke(cr);
546
547         cairo_destroy(cr);
548
549         return surface;
550 }
551
552 static void
553 panel_add_launcher(struct panel *panel, const char *icon, const char *path)
554 {
555         struct panel_launcher *launcher;
556         char *start, *p, *eq, **ps;
557         int i, j, k;
558
559         launcher = malloc(sizeof *launcher);
560         memset(launcher, 0, sizeof *launcher);
561         launcher->icon = load_icon_or_fallback(icon);
562         launcher->path = strdup(path);
563
564         wl_array_init(&launcher->envp);
565         wl_array_init(&launcher->argv);
566         for (i = 0; environ[i]; i++) {
567                 ps = wl_array_add(&launcher->envp, sizeof *ps);
568                 *ps = environ[i];
569         }
570         j = 0;
571
572         start = launcher->path;
573         while (*start) {
574                 for (p = start, eq = NULL; *p && !isspace(*p); p++)
575                         if (*p == '=')
576                                 eq = p;
577
578                 if (eq && j == 0) {
579                         ps = launcher->envp.data;
580                         for (k = 0; k < i; k++)
581                                 if (strncmp(ps[k], start, eq - start) == 0) {
582                                         ps[k] = start;
583                                         break;
584                                 }
585                         if (k == i) {
586                                 ps = wl_array_add(&launcher->envp, sizeof *ps);
587                                 *ps = start;
588                                 i++;
589                         }
590                 } else {
591                         ps = wl_array_add(&launcher->argv, sizeof *ps);
592                         *ps = start;
593                         j++;
594                 }
595
596                 while (*p && isspace(*p))
597                         *p++ = '\0';
598
599                 start = p;
600         }
601
602         ps = wl_array_add(&launcher->envp, sizeof *ps);
603         *ps = NULL;
604         ps = wl_array_add(&launcher->argv, sizeof *ps);
605         *ps = NULL;
606
607         launcher->panel = panel;
608         wl_list_insert(panel->launcher_list.prev, &launcher->link);
609
610         launcher->widget = widget_add_widget(panel->widget, launcher);
611         widget_set_enter_handler(launcher->widget,
612                                  panel_launcher_enter_handler);
613         widget_set_leave_handler(launcher->widget,
614                                    panel_launcher_leave_handler);
615         widget_set_button_handler(launcher->widget,
616                                     panel_launcher_button_handler);
617         widget_set_redraw_handler(launcher->widget,
618                                   panel_launcher_redraw_handler);
619         widget_set_motion_handler(launcher->widget,
620                                   panel_launcher_motion_handler);
621 }
622
623 enum {
624         BACKGROUND_SCALE,
625         BACKGROUND_TILE
626 };
627
628 static void
629 background_draw(struct widget *widget, void *data)
630 {
631         struct background *background = data;
632         cairo_surface_t *surface, *image;
633         cairo_pattern_t *pattern;
634         cairo_matrix_t matrix;
635         cairo_t *cr;
636         double sx, sy;
637         struct rectangle allocation;
638         int type = -1;
639         struct display *display;
640         struct wl_region *opaque;
641
642         surface = window_get_surface(background->window);
643
644         cr = cairo_create(surface);
645         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
646         cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
647         cairo_paint(cr);
648
649         widget_get_allocation(widget, &allocation);
650         image = NULL;
651         if (key_background_image)
652                 image = load_cairo_surface(key_background_image);
653
654         if (strcmp(key_background_type, "scale") == 0)
655                 type = BACKGROUND_SCALE;
656         else if (strcmp(key_background_type, "tile") == 0)
657                 type = BACKGROUND_TILE;
658         else
659                 fprintf(stderr, "invalid background-type: %s\n",
660                         key_background_type);
661
662         if (image && type != -1) {
663                 pattern = cairo_pattern_create_for_surface(image);
664                 switch (type) {
665                 case BACKGROUND_SCALE:
666                         sx = (double) cairo_image_surface_get_width(image) /
667                                 allocation.width;
668                         sy = (double) cairo_image_surface_get_height(image) /
669                                 allocation.height;
670                         cairo_matrix_init_scale(&matrix, sx, sy);
671                         cairo_pattern_set_matrix(pattern, &matrix);
672                         break;
673                 case BACKGROUND_TILE:
674                         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
675                         break;
676                 }
677                 cairo_set_source(cr, pattern);
678                 cairo_pattern_destroy (pattern);
679                 cairo_surface_destroy(image);
680         } else {
681                 set_hex_color(cr, key_background_color);
682         }
683
684         cairo_paint(cr);
685         cairo_destroy(cr);
686         cairo_surface_destroy(surface);
687
688         display = window_get_display(background->window);
689         opaque = wl_compositor_create_region(display_get_compositor(display));
690         wl_region_add(opaque, allocation.x, allocation.y,
691                       allocation.width, allocation.height);
692         wl_surface_set_opaque_region(window_get_wl_surface(background->window), opaque);
693         wl_region_destroy(opaque);
694 }
695
696 static void
697 background_configure(void *data,
698                      struct desktop_shell *desktop_shell,
699                      uint32_t edges, struct window *window,
700                      int32_t width, int32_t height)
701 {
702         struct background *background =
703                 (struct background *) window_get_user_data(window);
704
705         widget_schedule_resize(background->widget, width, height);
706 }
707
708 static void
709 unlock_dialog_redraw_handler(struct widget *widget, void *data)
710 {
711         struct unlock_dialog *dialog = data;
712         struct rectangle allocation;
713         cairo_t *cr;
714         cairo_surface_t *surface;
715         cairo_pattern_t *pat;
716         double cx, cy, r, f;
717
718         surface = window_get_surface(dialog->window);
719         cr = cairo_create(surface);
720
721         widget_get_allocation(dialog->widget, &allocation);
722         cairo_rectangle(cr, allocation.x, allocation.y,
723                         allocation.width, allocation.height);
724         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
725         cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
726         cairo_fill(cr);
727
728         cairo_translate(cr, allocation.x, allocation.y);
729         if (dialog->button_focused)
730                 f = 1.0;
731         else
732                 f = 0.7;
733
734         cx = allocation.width / 2.0;
735         cy = allocation.height / 2.0;
736         r = (cx < cy ? cx : cy) * 0.4;
737         pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
738         cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
739         cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
740         cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
741         cairo_set_source(cr, pat);
742         cairo_pattern_destroy(pat);
743         cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
744         cairo_fill(cr);
745
746         widget_set_allocation(dialog->button,
747                               allocation.x + cx - r,
748                               allocation.y + cy - r, 2 * r, 2 * r);
749
750         cairo_destroy(cr);
751
752         cairo_surface_destroy(surface);
753 }
754
755 static void
756 unlock_dialog_button_handler(struct widget *widget,
757                              struct input *input, uint32_t time,
758                              uint32_t button,
759                              enum wl_pointer_button_state state, void *data)
760 {
761         struct unlock_dialog *dialog = data;
762         struct desktop *desktop = dialog->desktop;
763
764         if (button == BTN_LEFT) {
765                 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
766                     !dialog->closing) {
767                         display_defer(desktop->display, &desktop->unlock_task);
768                         dialog->closing = 1;
769                 }
770         }
771 }
772
773 static void
774 unlock_dialog_keyboard_focus_handler(struct window *window,
775                                      struct input *device, void *data)
776 {
777         window_schedule_redraw(window);
778 }
779
780 static int
781 unlock_dialog_widget_enter_handler(struct widget *widget,
782                                    struct input *input,
783                                    float x, float y, void *data)
784 {
785         struct unlock_dialog *dialog = data;
786
787         dialog->button_focused = 1;
788         widget_schedule_redraw(widget);
789
790         return CURSOR_LEFT_PTR;
791 }
792
793 static void
794 unlock_dialog_widget_leave_handler(struct widget *widget,
795                                    struct input *input, void *data)
796 {
797         struct unlock_dialog *dialog = data;
798
799         dialog->button_focused = 0;
800         widget_schedule_redraw(widget);
801 }
802
803 static struct unlock_dialog *
804 unlock_dialog_create(struct desktop *desktop)
805 {
806         struct display *display = desktop->display;
807         struct unlock_dialog *dialog;
808
809         dialog = malloc(sizeof *dialog);
810         if (!dialog)
811                 return NULL;
812         memset(dialog, 0, sizeof *dialog);
813
814         dialog->window = window_create_custom(display);
815         dialog->widget = frame_create(dialog->window, dialog);
816         window_set_title(dialog->window, "Unlock your desktop");
817
818         window_set_user_data(dialog->window, dialog);
819         window_set_keyboard_focus_handler(dialog->window,
820                                           unlock_dialog_keyboard_focus_handler);
821         dialog->button = widget_add_widget(dialog->widget, dialog);
822         widget_set_redraw_handler(dialog->widget,
823                                   unlock_dialog_redraw_handler);
824         widget_set_enter_handler(dialog->button,
825                                  unlock_dialog_widget_enter_handler);
826         widget_set_leave_handler(dialog->button,
827                                  unlock_dialog_widget_leave_handler);
828         widget_set_button_handler(dialog->button,
829                                   unlock_dialog_button_handler);
830
831         desktop_shell_set_lock_surface(desktop->shell,
832                                        window_get_wl_surface(dialog->window));
833
834         window_schedule_resize(dialog->window, 260, 230);
835
836         return dialog;
837 }
838
839 static void
840 unlock_dialog_destroy(struct unlock_dialog *dialog)
841 {
842         window_destroy(dialog->window);
843         free(dialog);
844 }
845
846 static void
847 unlock_dialog_finish(struct task *task, uint32_t events)
848 {
849         struct desktop *desktop =
850                 container_of(task, struct desktop, unlock_task);
851
852         desktop_shell_unlock(desktop->shell);
853         unlock_dialog_destroy(desktop->unlock_dialog);
854         desktop->unlock_dialog = NULL;
855 }
856
857 static void
858 desktop_shell_configure(void *data,
859                         struct desktop_shell *desktop_shell,
860                         uint32_t edges,
861                         struct wl_surface *surface,
862                         int32_t width, int32_t height)
863 {
864         struct window *window = wl_surface_get_user_data(surface);
865         struct surface *s = window_get_user_data(window);
866
867         s->configure(data, desktop_shell, edges, window, width, height);
868 }
869
870 static void
871 desktop_shell_prepare_lock_surface(void *data,
872                                    struct desktop_shell *desktop_shell)
873 {
874         struct desktop *desktop = data;
875
876         if (!key_locking) {
877                 desktop_shell_unlock(desktop->shell);
878                 return;
879         }
880
881         if (!desktop->unlock_dialog) {
882                 desktop->unlock_dialog = unlock_dialog_create(desktop);
883                 desktop->unlock_dialog->desktop = desktop;
884         }
885 }
886
887 static void
888 desktop_shell_grab_cursor(void *data,
889                           struct desktop_shell *desktop_shell,
890                           uint32_t cursor)
891 {
892         struct desktop *desktop = data;
893
894         switch (cursor) {
895         case DESKTOP_SHELL_CURSOR_NONE:
896                 desktop->grab_cursor = CURSOR_BLANK;
897                 break;
898         case DESKTOP_SHELL_CURSOR_BUSY:
899                 desktop->grab_cursor = CURSOR_WATCH;
900                 break;
901         case DESKTOP_SHELL_CURSOR_MOVE:
902                 desktop->grab_cursor = CURSOR_DRAGGING;
903                 break;
904         case DESKTOP_SHELL_CURSOR_RESIZE_TOP:
905                 desktop->grab_cursor = CURSOR_TOP;
906                 break;
907         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM:
908                 desktop->grab_cursor = CURSOR_BOTTOM;
909                 break;
910         case DESKTOP_SHELL_CURSOR_RESIZE_LEFT:
911                 desktop->grab_cursor = CURSOR_LEFT;
912                 break;
913         case DESKTOP_SHELL_CURSOR_RESIZE_RIGHT:
914                 desktop->grab_cursor = CURSOR_RIGHT;
915                 break;
916         case DESKTOP_SHELL_CURSOR_RESIZE_TOP_LEFT:
917                 desktop->grab_cursor = CURSOR_TOP_LEFT;
918                 break;
919         case DESKTOP_SHELL_CURSOR_RESIZE_TOP_RIGHT:
920                 desktop->grab_cursor = CURSOR_TOP_RIGHT;
921                 break;
922         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_LEFT:
923                 desktop->grab_cursor = CURSOR_BOTTOM_LEFT;
924                 break;
925         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_RIGHT:
926                 desktop->grab_cursor = CURSOR_BOTTOM_RIGHT;
927                 break;
928         case DESKTOP_SHELL_CURSOR_ARROW:
929         default:
930                 desktop->grab_cursor = CURSOR_LEFT_PTR;
931         }
932 }
933
934 static const struct desktop_shell_listener listener = {
935         desktop_shell_configure,
936         desktop_shell_prepare_lock_surface,
937         desktop_shell_grab_cursor
938 };
939
940 static void
941 background_destroy(struct background *background)
942 {
943         widget_destroy(background->widget);
944         window_destroy(background->window);
945
946         free(background);
947 }
948
949 static struct background *
950 background_create(struct desktop *desktop)
951 {
952         struct background *background;
953
954         background = malloc(sizeof *background);
955         memset(background, 0, sizeof *background);
956
957         background->base.configure = background_configure;
958         background->window = window_create_custom(desktop->display);
959         background->widget = window_add_widget(background->window, background);
960         window_set_user_data(background->window, background);
961         widget_set_redraw_handler(background->widget, background_draw);
962
963         return background;
964 }
965
966 static int
967 grab_surface_enter_handler(struct widget *widget, struct input *input,
968                            float x, float y, void *data)
969 {
970         struct desktop *desktop = data;
971
972         return desktop->grab_cursor;
973 }
974
975 static void
976 grab_surface_destroy(struct desktop *desktop)
977 {
978         widget_destroy(desktop->grab_widget);
979         window_destroy(desktop->grab_window);
980 }
981
982 static void
983 grab_surface_create(struct desktop *desktop)
984 {
985         struct wl_surface *s;
986
987         desktop->grab_window = window_create_custom(desktop->display);
988         window_set_user_data(desktop->grab_window, desktop);
989
990         s = window_get_wl_surface(desktop->grab_window);
991         desktop_shell_set_grab_surface(desktop->shell, s);
992
993         desktop->grab_widget =
994                 window_add_widget(desktop->grab_window, desktop);
995         /* We set the allocation to 1x1 at 0,0 so the fake enter event
996          * at 0,0 will go to this widget. */
997         widget_set_allocation(desktop->grab_widget, 0, 0, 1, 1);
998
999         widget_set_enter_handler(desktop->grab_widget,
1000                                  grab_surface_enter_handler);
1001 }
1002
1003 static void
1004 output_destroy(struct output *output)
1005 {
1006         background_destroy(output->background);
1007         panel_destroy(output->panel);
1008         wl_output_destroy(output->output);
1009         wl_list_remove(&output->link);
1010
1011         free(output);
1012 }
1013
1014 static void
1015 desktop_destroy_outputs(struct desktop *desktop)
1016 {
1017         struct output *tmp;
1018         struct output *output;
1019
1020         wl_list_for_each_safe(output, tmp, &desktop->outputs, link)
1021                 output_destroy(output);
1022 }
1023
1024 static void
1025 create_output(struct desktop *desktop, uint32_t id)
1026 {
1027         struct output *output;
1028
1029         output = calloc(1, sizeof *output);
1030         if (!output)
1031                 return;
1032
1033         output->output =
1034                 display_bind(desktop->display, id, &wl_output_interface, 1);
1035
1036         wl_list_insert(&desktop->outputs, &output->link);
1037 }
1038
1039 static void
1040 global_handler(struct display *display, uint32_t id,
1041                const char *interface, uint32_t version, void *data)
1042 {
1043         struct desktop *desktop = data;
1044
1045         if (!strcmp(interface, "desktop_shell")) {
1046                 desktop->shell = display_bind(desktop->display,
1047                                               id, &desktop_shell_interface, 1);
1048                 desktop_shell_add_listener(desktop->shell, &listener, desktop);
1049         } else if (!strcmp(interface, "wl_output")) {
1050                 create_output(desktop, id);
1051         }
1052 }
1053
1054 static void
1055 launcher_section_done(void *data)
1056 {
1057         struct desktop *desktop = data;
1058         struct output *output;
1059
1060         if (key_launcher_icon == NULL || key_launcher_path == NULL) {
1061                 fprintf(stderr, "invalid launcher section\n");
1062                 return;
1063         }
1064
1065         wl_list_for_each(output, &desktop->outputs, link) {
1066                 panel_add_launcher(output->panel,
1067                                    key_launcher_icon, key_launcher_path);
1068         }
1069
1070         free(key_launcher_icon);
1071         key_launcher_icon = NULL;
1072         free(key_launcher_path);
1073         key_launcher_path = NULL;
1074 }
1075
1076 static void
1077 add_default_launcher(struct desktop *desktop)
1078 {
1079         struct output *output;
1080
1081         wl_list_for_each(output, &desktop->outputs, link)
1082                 panel_add_launcher(output->panel,
1083                                    DATADIR "/weston/terminal.png",
1084                                    BINDIR "/weston-terminal");
1085 }
1086
1087 int main(int argc, char *argv[])
1088 {
1089         struct desktop desktop = { 0 };
1090         char *config_file;
1091         struct output *output;
1092         int ret;
1093
1094         desktop.unlock_task.run = unlock_dialog_finish;
1095         wl_list_init(&desktop.outputs);
1096
1097         desktop.display = display_create(argc, argv);
1098         if (desktop.display == NULL) {
1099                 fprintf(stderr, "failed to create display: %m\n");
1100                 return -1;
1101         }
1102
1103         display_set_user_data(desktop.display, &desktop);
1104         display_set_global_handler(desktop.display, global_handler);
1105
1106         wl_list_for_each(output, &desktop.outputs, link) {
1107                 struct wl_surface *surface;
1108
1109                 output->panel = panel_create(desktop.display);
1110                 surface = window_get_wl_surface(output->panel->window);
1111                 desktop_shell_set_panel(desktop.shell,
1112                                         output->output, surface);
1113
1114                 output->background = background_create(&desktop);
1115                 surface = window_get_wl_surface(output->background->window);
1116                 desktop_shell_set_background(desktop.shell,
1117                                              output->output, surface);
1118         }
1119
1120         grab_surface_create(&desktop);
1121
1122         config_file = config_file_path("weston.ini");
1123         ret = parse_config_file(config_file,
1124                                 config_sections, ARRAY_LENGTH(config_sections),
1125                                 &desktop);
1126         free(config_file);
1127         if (ret < 0)
1128                 add_default_launcher(&desktop);
1129
1130         signal(SIGCHLD, sigchild_handler);
1131
1132         display_run(desktop.display);
1133
1134         /* Cleanup */
1135         grab_surface_destroy(&desktop);
1136         desktop_destroy_outputs(&desktop);
1137         if (desktop.unlock_dialog)
1138                 unlock_dialog_destroy(desktop.unlock_dialog);
1139         desktop_shell_destroy(desktop.shell);
1140         display_destroy(desktop.display);
1141
1142         return 0;
1143 }