Update to new fd and wl_registry APIs
[platform/upstream/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
640         surface = window_get_surface(background->window);
641
642         cr = cairo_create(surface);
643         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
644         cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
645         cairo_paint(cr);
646
647         widget_get_allocation(widget, &allocation);
648         image = NULL;
649         if (key_background_image)
650                 image = load_cairo_surface(key_background_image);
651
652         if (strcmp(key_background_type, "scale") == 0)
653                 type = BACKGROUND_SCALE;
654         else if (strcmp(key_background_type, "tile") == 0)
655                 type = BACKGROUND_TILE;
656         else
657                 fprintf(stderr, "invalid background-type: %s\n",
658                         key_background_type);
659
660         if (image && type != -1) {
661                 pattern = cairo_pattern_create_for_surface(image);
662                 switch (type) {
663                 case BACKGROUND_SCALE:
664                         sx = (double) cairo_image_surface_get_width(image) /
665                                 allocation.width;
666                         sy = (double) cairo_image_surface_get_height(image) /
667                                 allocation.height;
668                         cairo_matrix_init_scale(&matrix, sx, sy);
669                         cairo_pattern_set_matrix(pattern, &matrix);
670                         break;
671                 case BACKGROUND_TILE:
672                         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
673                         break;
674                 }
675                 cairo_set_source(cr, pattern);
676                 cairo_pattern_destroy (pattern);
677                 cairo_surface_destroy(image);
678         } else {
679                 set_hex_color(cr, key_background_color);
680         }
681
682         cairo_paint(cr);
683         cairo_destroy(cr);
684         cairo_surface_destroy(surface);
685 }
686
687 static void
688 background_configure(void *data,
689                      struct desktop_shell *desktop_shell,
690                      uint32_t edges, struct window *window,
691                      int32_t width, int32_t height)
692 {
693         struct background *background =
694                 (struct background *) window_get_user_data(window);
695
696         widget_schedule_resize(background->widget, width, height);
697 }
698
699 static void
700 unlock_dialog_redraw_handler(struct widget *widget, void *data)
701 {
702         struct unlock_dialog *dialog = data;
703         struct rectangle allocation;
704         cairo_t *cr;
705         cairo_surface_t *surface;
706         cairo_pattern_t *pat;
707         double cx, cy, r, f;
708
709         surface = window_get_surface(dialog->window);
710         cr = cairo_create(surface);
711
712         widget_get_allocation(dialog->widget, &allocation);
713         cairo_rectangle(cr, allocation.x, allocation.y,
714                         allocation.width, allocation.height);
715         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
716         cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
717         cairo_fill(cr);
718
719         cairo_translate(cr, allocation.x, allocation.y);
720         if (dialog->button_focused)
721                 f = 1.0;
722         else
723                 f = 0.7;
724
725         cx = allocation.width / 2.0;
726         cy = allocation.height / 2.0;
727         r = (cx < cy ? cx : cy) * 0.4;
728         pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
729         cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
730         cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
731         cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
732         cairo_set_source(cr, pat);
733         cairo_pattern_destroy(pat);
734         cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
735         cairo_fill(cr);
736
737         widget_set_allocation(dialog->button,
738                               allocation.x + cx - r,
739                               allocation.y + cy - r, 2 * r, 2 * r);
740
741         cairo_destroy(cr);
742
743         cairo_surface_destroy(surface);
744 }
745
746 static void
747 unlock_dialog_button_handler(struct widget *widget,
748                              struct input *input, uint32_t time,
749                              uint32_t button,
750                              enum wl_pointer_button_state state, void *data)
751 {
752         struct unlock_dialog *dialog = data;
753         struct desktop *desktop = dialog->desktop;
754
755         if (button == BTN_LEFT) {
756                 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
757                     !dialog->closing) {
758                         display_defer(desktop->display, &desktop->unlock_task);
759                         dialog->closing = 1;
760                 }
761         }
762 }
763
764 static void
765 unlock_dialog_keyboard_focus_handler(struct window *window,
766                                      struct input *device, void *data)
767 {
768         window_schedule_redraw(window);
769 }
770
771 static int
772 unlock_dialog_widget_enter_handler(struct widget *widget,
773                                    struct input *input,
774                                    float x, float y, void *data)
775 {
776         struct unlock_dialog *dialog = data;
777
778         dialog->button_focused = 1;
779         widget_schedule_redraw(widget);
780
781         return CURSOR_LEFT_PTR;
782 }
783
784 static void
785 unlock_dialog_widget_leave_handler(struct widget *widget,
786                                    struct input *input, void *data)
787 {
788         struct unlock_dialog *dialog = data;
789
790         dialog->button_focused = 0;
791         widget_schedule_redraw(widget);
792 }
793
794 static struct unlock_dialog *
795 unlock_dialog_create(struct desktop *desktop)
796 {
797         struct display *display = desktop->display;
798         struct unlock_dialog *dialog;
799
800         dialog = malloc(sizeof *dialog);
801         if (!dialog)
802                 return NULL;
803         memset(dialog, 0, sizeof *dialog);
804
805         dialog->window = window_create_custom(display);
806         dialog->widget = frame_create(dialog->window, dialog);
807         window_set_title(dialog->window, "Unlock your desktop");
808
809         window_set_user_data(dialog->window, dialog);
810         window_set_keyboard_focus_handler(dialog->window,
811                                           unlock_dialog_keyboard_focus_handler);
812         dialog->button = widget_add_widget(dialog->widget, dialog);
813         widget_set_redraw_handler(dialog->widget,
814                                   unlock_dialog_redraw_handler);
815         widget_set_enter_handler(dialog->button,
816                                  unlock_dialog_widget_enter_handler);
817         widget_set_leave_handler(dialog->button,
818                                  unlock_dialog_widget_leave_handler);
819         widget_set_button_handler(dialog->button,
820                                   unlock_dialog_button_handler);
821
822         desktop_shell_set_lock_surface(desktop->shell,
823                                        window_get_wl_surface(dialog->window));
824
825         window_schedule_resize(dialog->window, 260, 230);
826
827         return dialog;
828 }
829
830 static void
831 unlock_dialog_destroy(struct unlock_dialog *dialog)
832 {
833         window_destroy(dialog->window);
834         free(dialog);
835 }
836
837 static void
838 unlock_dialog_finish(struct task *task, uint32_t events)
839 {
840         struct desktop *desktop =
841                 container_of(task, struct desktop, unlock_task);
842
843         desktop_shell_unlock(desktop->shell);
844         unlock_dialog_destroy(desktop->unlock_dialog);
845         desktop->unlock_dialog = NULL;
846 }
847
848 static void
849 desktop_shell_configure(void *data,
850                         struct desktop_shell *desktop_shell,
851                         uint32_t edges,
852                         struct wl_surface *surface,
853                         int32_t width, int32_t height)
854 {
855         struct window *window = wl_surface_get_user_data(surface);
856         struct surface *s = window_get_user_data(window);
857
858         s->configure(data, desktop_shell, edges, window, width, height);
859 }
860
861 static void
862 desktop_shell_prepare_lock_surface(void *data,
863                                    struct desktop_shell *desktop_shell)
864 {
865         struct desktop *desktop = data;
866
867         if (!key_locking) {
868                 desktop_shell_unlock(desktop->shell);
869                 return;
870         }
871
872         if (!desktop->unlock_dialog) {
873                 desktop->unlock_dialog = unlock_dialog_create(desktop);
874                 desktop->unlock_dialog->desktop = desktop;
875         }
876 }
877
878 static void
879 desktop_shell_grab_cursor(void *data,
880                           struct desktop_shell *desktop_shell,
881                           uint32_t cursor)
882 {
883         struct desktop *desktop = data;
884
885         switch (cursor) {
886         case DESKTOP_SHELL_CURSOR_NONE:
887                 desktop->grab_cursor = CURSOR_BLANK;
888                 break;
889         case DESKTOP_SHELL_CURSOR_BUSY:
890                 desktop->grab_cursor = CURSOR_WATCH;
891                 break;
892         case DESKTOP_SHELL_CURSOR_MOVE:
893                 desktop->grab_cursor = CURSOR_DRAGGING;
894                 break;
895         case DESKTOP_SHELL_CURSOR_RESIZE_TOP:
896                 desktop->grab_cursor = CURSOR_TOP;
897                 break;
898         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM:
899                 desktop->grab_cursor = CURSOR_BOTTOM;
900                 break;
901         case DESKTOP_SHELL_CURSOR_RESIZE_LEFT:
902                 desktop->grab_cursor = CURSOR_LEFT;
903                 break;
904         case DESKTOP_SHELL_CURSOR_RESIZE_RIGHT:
905                 desktop->grab_cursor = CURSOR_RIGHT;
906                 break;
907         case DESKTOP_SHELL_CURSOR_RESIZE_TOP_LEFT:
908                 desktop->grab_cursor = CURSOR_TOP_LEFT;
909                 break;
910         case DESKTOP_SHELL_CURSOR_RESIZE_TOP_RIGHT:
911                 desktop->grab_cursor = CURSOR_TOP_RIGHT;
912                 break;
913         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_LEFT:
914                 desktop->grab_cursor = CURSOR_BOTTOM_LEFT;
915                 break;
916         case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_RIGHT:
917                 desktop->grab_cursor = CURSOR_BOTTOM_RIGHT;
918                 break;
919         case DESKTOP_SHELL_CURSOR_ARROW:
920         default:
921                 desktop->grab_cursor = CURSOR_LEFT_PTR;
922         }
923 }
924
925 static const struct desktop_shell_listener listener = {
926         desktop_shell_configure,
927         desktop_shell_prepare_lock_surface,
928         desktop_shell_grab_cursor
929 };
930
931 static void
932 background_destroy(struct background *background)
933 {
934         widget_destroy(background->widget);
935         window_destroy(background->window);
936
937         free(background);
938 }
939
940 static struct background *
941 background_create(struct desktop *desktop)
942 {
943         struct background *background;
944
945         background = malloc(sizeof *background);
946         memset(background, 0, sizeof *background);
947
948         background->base.configure = background_configure;
949         background->window = window_create_custom(desktop->display);
950         background->widget = window_add_widget(background->window, background);
951         window_set_user_data(background->window, background);
952         widget_set_redraw_handler(background->widget, background_draw);
953
954         return background;
955 }
956
957 static int
958 grab_surface_enter_handler(struct widget *widget, struct input *input,
959                            float x, float y, void *data)
960 {
961         struct desktop *desktop = data;
962
963         return desktop->grab_cursor;
964 }
965
966 static void
967 grab_surface_destroy(struct desktop *desktop)
968 {
969         widget_destroy(desktop->grab_widget);
970         window_destroy(desktop->grab_window);
971 }
972
973 static void
974 grab_surface_create(struct desktop *desktop)
975 {
976         struct wl_surface *s;
977
978         desktop->grab_window = window_create_custom(desktop->display);
979         window_set_user_data(desktop->grab_window, desktop);
980
981         s = window_get_wl_surface(desktop->grab_window);
982         desktop_shell_set_grab_surface(desktop->shell, s);
983
984         desktop->grab_widget =
985                 window_add_widget(desktop->grab_window, desktop);
986         /* We set the allocation to 1x1 at 0,0 so the fake enter event
987          * at 0,0 will go to this widget. */
988         widget_set_allocation(desktop->grab_widget, 0, 0, 1, 1);
989
990         widget_set_enter_handler(desktop->grab_widget,
991                                  grab_surface_enter_handler);
992 }
993
994 static void
995 output_destroy(struct output *output)
996 {
997         background_destroy(output->background);
998         panel_destroy(output->panel);
999         wl_output_destroy(output->output);
1000         wl_list_remove(&output->link);
1001
1002         free(output);
1003 }
1004
1005 static void
1006 desktop_destroy_outputs(struct desktop *desktop)
1007 {
1008         struct output *tmp;
1009         struct output *output;
1010
1011         wl_list_for_each_safe(output, tmp, &desktop->outputs, link)
1012                 output_destroy(output);
1013 }
1014
1015 static void
1016 create_output(struct desktop *desktop, uint32_t id)
1017 {
1018         struct output *output;
1019
1020         output = calloc(1, sizeof *output);
1021         if (!output)
1022                 return;
1023
1024         output->output =
1025                 display_bind(desktop->display, id, &wl_output_interface, 1);
1026
1027         wl_list_insert(&desktop->outputs, &output->link);
1028 }
1029
1030 static void
1031 global_handler(struct display *display, uint32_t id,
1032                const char *interface, uint32_t version, void *data)
1033 {
1034         struct desktop *desktop = data;
1035
1036         if (!strcmp(interface, "desktop_shell")) {
1037                 desktop->shell = display_bind(desktop->display,
1038                                               id, &desktop_shell_interface, 1);
1039                 desktop_shell_add_listener(desktop->shell, &listener, desktop);
1040         } else if (!strcmp(interface, "wl_output")) {
1041                 create_output(desktop, id);
1042         }
1043 }
1044
1045 static void
1046 launcher_section_done(void *data)
1047 {
1048         struct desktop *desktop = data;
1049         struct output *output;
1050
1051         if (key_launcher_icon == NULL || key_launcher_path == NULL) {
1052                 fprintf(stderr, "invalid launcher section\n");
1053                 return;
1054         }
1055
1056         wl_list_for_each(output, &desktop->outputs, link) {
1057                 panel_add_launcher(output->panel,
1058                                    key_launcher_icon, key_launcher_path);
1059         }
1060
1061         free(key_launcher_icon);
1062         key_launcher_icon = NULL;
1063         free(key_launcher_path);
1064         key_launcher_path = NULL;
1065 }
1066
1067 static void
1068 add_default_launcher(struct desktop *desktop)
1069 {
1070         struct output *output;
1071
1072         wl_list_for_each(output, &desktop->outputs, link)
1073                 panel_add_launcher(output->panel,
1074                                    DATADIR "/weston/terminal.png",
1075                                    BINDIR "/weston-terminal");
1076 }
1077
1078 int main(int argc, char *argv[])
1079 {
1080         struct desktop desktop = { 0 };
1081         char *config_file;
1082         struct output *output;
1083         int ret;
1084
1085         desktop.unlock_task.run = unlock_dialog_finish;
1086         wl_list_init(&desktop.outputs);
1087
1088         desktop.display = display_create(argc, argv);
1089         if (desktop.display == NULL) {
1090                 fprintf(stderr, "failed to create display: %m\n");
1091                 return -1;
1092         }
1093
1094         display_set_user_data(desktop.display, &desktop);
1095         display_set_global_handler(desktop.display, global_handler);
1096
1097         wl_list_for_each(output, &desktop.outputs, link) {
1098                 struct wl_surface *surface;
1099
1100                 output->panel = panel_create(desktop.display);
1101                 surface = window_get_wl_surface(output->panel->window);
1102                 desktop_shell_set_panel(desktop.shell,
1103                                         output->output, surface);
1104
1105                 output->background = background_create(&desktop);
1106                 surface = window_get_wl_surface(output->background->window);
1107                 desktop_shell_set_background(desktop.shell,
1108                                              output->output, surface);
1109         }
1110
1111         grab_surface_create(&desktop);
1112
1113         config_file = config_file_path("weston.ini");
1114         ret = parse_config_file(config_file,
1115                                 config_sections, ARRAY_LENGTH(config_sections),
1116                                 &desktop);
1117         free(config_file);
1118         if (ret < 0)
1119                 add_default_launcher(&desktop);
1120
1121         signal(SIGCHLD, sigchild_handler);
1122
1123         display_run(desktop.display);
1124
1125         /* Cleanup */
1126         grab_surface_destroy(&desktop);
1127         desktop_destroy_outputs(&desktop);
1128         if (desktop.unlock_dialog)
1129                 unlock_dialog_destroy(desktop.unlock_dialog);
1130         desktop_shell_destroy(desktop.shell);
1131         display_destroy(desktop.display);
1132
1133         return 0;
1134 }