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