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