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