window: use libwayland-cursor instead of libXcursor
[platform/upstream/weston.git] / clients / desktop-shell.c
1 /*
2  * Copyright © 2011 Kristian Høgsberg
3  * Copyright © 2011 Collabora, Ltd.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <math.h>
31 #include <cairo.h>
32 #include <sys/wait.h>
33 #include <linux/input.h>
34
35 #include <wayland-client.h>
36 #include <wayland-cursor.h>
37 #include "window.h"
38 #include "../shared/cairo-util.h"
39 #include "../shared/config-parser.h"
40
41 #include "desktop-shell-client-protocol.h"
42
43 struct desktop {
44         struct display *display;
45         struct desktop_shell *shell;
46         struct unlock_dialog *unlock_dialog;
47         struct task unlock_task;
48         struct wl_list outputs;
49 };
50
51 struct surface {
52         void (*configure)(void *data,
53                           struct desktop_shell *desktop_shell,
54                           uint32_t edges, struct window *window,
55                           int32_t width, int32_t height);
56 };
57
58 struct panel {
59         struct surface base;
60         struct window *window;
61         struct widget *widget;
62         struct wl_list launcher_list;
63 };
64
65 struct background {
66         struct surface base;
67         struct window *window;
68         struct widget *widget;
69 };
70
71 struct output {
72         struct wl_output *output;
73         struct wl_list link;
74
75         struct panel *panel;
76         struct background *background;
77 };
78
79 struct panel_launcher {
80         struct widget *widget;
81         struct panel *panel;
82         cairo_surface_t *icon;
83         int focused, pressed;
84         const char *path;
85         struct wl_list link;
86 };
87
88 struct unlock_dialog {
89         struct window *window;
90         struct widget *widget;
91         struct widget *button;
92         int button_focused;
93         int closing;
94
95         struct desktop *desktop;
96 };
97
98 static char *key_background_image = DATADIR "/weston/pattern.png";
99 static char *key_background_type = "tile";
100 static uint32_t key_panel_color = 0xaa000000;
101 static uint32_t key_background_color = 0xff002244;
102 static char *key_launcher_icon;
103 static char *key_launcher_path;
104 static void launcher_section_done(void *data);
105 static int key_locking = 1;
106
107 static const struct config_key shell_config_keys[] = {
108         { "background-image", CONFIG_KEY_STRING, &key_background_image },
109         { "background-type", CONFIG_KEY_STRING, &key_background_type },
110         { "panel-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_panel_color },
111         { "background-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_background_color },
112         { "locking", CONFIG_KEY_BOOLEAN, &key_locking },
113 };
114
115 static const struct config_key launcher_config_keys[] = {
116         { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
117         { "path", CONFIG_KEY_STRING, &key_launcher_path },
118 };
119
120 static const struct config_section config_sections[] = {
121         { "shell",
122           shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
123         { "launcher",
124           launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
125           launcher_section_done }
126 };
127
128 static void
129 sigchild_handler(int s)
130 {
131         int status;
132         pid_t pid;
133
134         while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
135                 fprintf(stderr, "child %d exited\n", pid);
136 }
137
138 static void
139 menu_func(struct window *window, int index, void *data)
140 {
141         printf("Selected index %d from a panel menu.\n", index);
142 }
143
144 static void
145 show_menu(struct panel *panel, struct input *input, uint32_t time)
146 {
147         int32_t x, y;
148         static const char *entries[] = {
149                 "Roy", "Pris", "Leon", "Zhora"
150         };
151
152         input_get_position(input, &x, &y);
153         window_show_menu(window_get_display(panel->window),
154                          input, time, panel->window,
155                          x - 10, y - 10, menu_func, entries, 4);
156 }
157
158 static void
159 panel_launcher_activate(struct panel_launcher *widget)
160 {
161         pid_t pid;
162
163         pid = fork();
164         if (pid < 0) {
165                 fprintf(stderr, "fork failed: %m\n");
166                 return;
167         }
168
169         if (pid)
170                 return;
171
172         if (execl(widget->path, widget->path, NULL) < 0) {
173                 fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
174                 exit(1);
175         }
176 }
177
178 static void
179 panel_launcher_redraw_handler(struct widget *widget, void *data)
180 {
181         struct panel_launcher *launcher = data;
182         cairo_surface_t *surface;
183         struct rectangle allocation;
184         cairo_t *cr;
185
186         surface = window_get_surface(launcher->panel->window);
187         cr = cairo_create(surface);
188
189         widget_get_allocation(widget, &allocation);
190         if (launcher->pressed) {
191                 allocation.x++;
192                 allocation.y++;
193         }
194
195         cairo_set_source_surface(cr, launcher->icon,
196                                  allocation.x, allocation.y);
197         cairo_paint(cr);
198
199         if (launcher->focused) {
200                 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
201                 cairo_mask_surface(cr, launcher->icon,
202                                    allocation.x, allocation.y);
203         }
204
205         cairo_destroy(cr);
206 }
207
208 static void
209 set_hex_color(cairo_t *cr, uint32_t color)
210 {
211         cairo_set_source_rgba(cr, 
212                               ((color >> 16) & 0xff) / 255.0,
213                               ((color >>  8) & 0xff) / 255.0,
214                               ((color >>  0) & 0xff) / 255.0,
215                               ((color >> 24) & 0xff) / 255.0);
216 }
217
218 static void
219 panel_redraw_handler(struct widget *widget, void *data)
220 {
221         cairo_surface_t *surface;
222         cairo_t *cr;
223         struct panel *panel = data;
224
225         surface = window_get_surface(panel->window);
226         cr = cairo_create(surface);
227         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
228         set_hex_color(cr, key_panel_color);
229         cairo_paint(cr);
230
231         cairo_destroy(cr);
232         cairo_surface_destroy(surface);
233 }
234
235 static int
236 panel_launcher_enter_handler(struct widget *widget, struct input *input,
237                              float x, float y, void *data)
238 {
239         struct panel_launcher *launcher = data;
240
241         launcher->focused = 1;
242         widget_schedule_redraw(widget);
243
244         return WL_CURSOR_LEFT_PTR;
245 }
246
247 static void
248 panel_launcher_leave_handler(struct widget *widget,
249                              struct input *input, void *data)
250 {
251         struct panel_launcher *launcher = data;
252
253         launcher->focused = 0;
254         widget_schedule_redraw(widget);
255 }
256
257 static void
258 panel_launcher_button_handler(struct widget *widget,
259                               struct input *input, uint32_t time,
260                               uint32_t button, uint32_t state, void *data)
261 {
262         struct panel_launcher *launcher;
263
264         launcher = widget_get_user_data(widget);
265         widget_schedule_redraw(widget);
266         if (state == 0)
267                 panel_launcher_activate(launcher);
268 }
269
270 static void
271 panel_button_handler(struct widget *widget,
272                      struct input *input, uint32_t time,
273                      uint32_t button, uint32_t state, void *data)
274 {
275         struct panel *panel = data;
276
277         if (button == BTN_RIGHT && state)
278                 show_menu(panel, input, time);
279 }
280
281 static void
282 panel_resize_handler(struct widget *widget,
283                      int32_t width, int32_t height, void *data)
284 {
285         struct panel_launcher *launcher;
286         struct panel *panel = data;
287         int x, y, w, h;
288         
289         x = 10;
290         y = 16;
291         wl_list_for_each(launcher, &panel->launcher_list, link) {
292                 w = cairo_image_surface_get_width(launcher->icon);
293                 h = cairo_image_surface_get_height(launcher->icon);
294                 widget_set_allocation(launcher->widget,
295                                       x, y - h / 2, w + 1, h + 1);
296                 x += w + 10;
297         }
298 }
299
300 static void
301 panel_configure(void *data,
302                 struct desktop_shell *desktop_shell,
303                 uint32_t edges, struct window *window,
304                 int32_t width, int32_t height)
305 {
306         struct surface *surface = window_get_user_data(window);
307         struct panel *panel = container_of(surface, struct panel, base);
308
309         window_schedule_resize(panel->window, width, 32);
310 }
311
312 static struct panel *
313 panel_create(struct display *display)
314 {
315         struct panel *panel;
316
317         panel = malloc(sizeof *panel);
318         memset(panel, 0, sizeof *panel);
319
320         panel->base.configure = panel_configure;
321         panel->window = window_create(display);
322         panel->widget = window_add_widget(panel->window, panel);
323         wl_list_init(&panel->launcher_list);
324
325         window_set_title(panel->window, "panel");
326         window_set_custom(panel->window);
327         window_set_user_data(panel->window, panel);
328
329         widget_set_redraw_handler(panel->widget, panel_redraw_handler);
330         widget_set_resize_handler(panel->widget, panel_resize_handler);
331         widget_set_button_handler(panel->widget, panel_button_handler);
332
333         return panel;
334 }
335
336 static void
337 panel_add_launcher(struct panel *panel, const char *icon, const char *path)
338 {
339         struct panel_launcher *launcher;
340
341         launcher = malloc(sizeof *launcher);
342         memset(launcher, 0, sizeof *launcher);
343         launcher->icon = cairo_image_surface_create_from_png(icon);
344         launcher->path = strdup(path);
345         launcher->panel = panel;
346         wl_list_insert(panel->launcher_list.prev, &launcher->link);
347
348         launcher->widget = widget_add_widget(panel->widget, launcher);
349         widget_set_enter_handler(launcher->widget,
350                                  panel_launcher_enter_handler);
351         widget_set_leave_handler(launcher->widget,
352                                    panel_launcher_leave_handler);
353         widget_set_button_handler(launcher->widget,
354                                     panel_launcher_button_handler);
355         widget_set_redraw_handler(launcher->widget,
356                                   panel_launcher_redraw_handler);
357 }
358
359 enum {
360         BACKGROUND_SCALE,
361         BACKGROUND_TILE
362 };
363
364 static void
365 background_draw(struct widget *widget, void *data)
366 {
367         struct background *background = data;
368         cairo_surface_t *surface, *image;
369         cairo_pattern_t *pattern;
370         cairo_matrix_t matrix;
371         cairo_t *cr;
372         double sx, sy;
373         struct rectangle allocation;
374         int type = -1;
375
376         surface = window_get_surface(background->window);
377
378         cr = cairo_create(surface);
379         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
380         cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
381         cairo_paint(cr);
382
383         widget_get_allocation(widget, &allocation);
384         image = NULL;
385         if (key_background_image)
386                 image = load_cairo_surface(key_background_image);
387
388         if (strcmp(key_background_type, "scale") == 0)
389                 type = BACKGROUND_SCALE;
390         else if (strcmp(key_background_type, "tile") == 0)
391                 type = BACKGROUND_TILE;
392         else
393                 fprintf(stderr, "invalid background-type: %s\n",
394                         key_background_type);
395
396         if (image && type != -1) {
397                 pattern = cairo_pattern_create_for_surface(image);
398                 switch (type) {
399                 case BACKGROUND_SCALE:
400                         sx = (double) cairo_image_surface_get_width(image) /
401                                 allocation.width;
402                         sy = (double) cairo_image_surface_get_height(image) /
403                                 allocation.height;
404                         cairo_matrix_init_scale(&matrix, sx, sy);
405                         cairo_pattern_set_matrix(pattern, &matrix);
406                         break;
407                 case BACKGROUND_TILE:
408                         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
409                         break;
410                 }
411                 cairo_set_source(cr, pattern);
412                 cairo_pattern_destroy (pattern);
413                 cairo_surface_destroy(image);
414         } else {
415                 set_hex_color(cr, key_background_color);
416         }
417
418         cairo_paint(cr);
419         cairo_destroy(cr);
420         cairo_surface_destroy(surface);
421 }
422
423 static void
424 background_configure(void *data,
425                      struct desktop_shell *desktop_shell,
426                      uint32_t edges, struct window *window,
427                      int32_t width, int32_t height)
428 {
429         struct background *background =
430                 (struct background *) window_get_user_data(window);
431
432         widget_schedule_resize(background->widget, width, height);
433 }
434
435 static void
436 unlock_dialog_redraw_handler(struct widget *widget, void *data)
437 {
438         struct unlock_dialog *dialog = data;
439         struct rectangle allocation;
440         cairo_t *cr;
441         cairo_surface_t *surface;
442         cairo_pattern_t *pat;
443         double cx, cy, r, f;
444
445         surface = window_get_surface(dialog->window);
446         cr = cairo_create(surface);
447
448         widget_get_allocation(dialog->widget, &allocation);
449         cairo_rectangle(cr, allocation.x, allocation.y,
450                         allocation.width, allocation.height);
451         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
452         cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
453         cairo_fill(cr);
454
455         cairo_translate(cr, allocation.x, allocation.y);
456         if (dialog->button_focused)
457                 f = 1.0;
458         else
459                 f = 0.7;
460
461         cx = allocation.width / 2.0;
462         cy = allocation.height / 2.0;
463         r = (cx < cy ? cx : cy) * 0.4;
464         pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
465         cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
466         cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
467         cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
468         cairo_set_source(cr, pat);
469         cairo_pattern_destroy(pat);
470         cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
471         cairo_fill(cr);
472
473         widget_set_allocation(dialog->button,
474                               allocation.x + cx - r,
475                               allocation.y + cy - r, 2 * r, 2 * r);
476
477         cairo_destroy(cr);
478
479         cairo_surface_destroy(surface);
480 }
481
482 static void
483 unlock_dialog_button_handler(struct widget *widget,
484                              struct input *input, uint32_t time,
485                              uint32_t button, uint32_t state, void *data)
486 {
487         struct unlock_dialog *dialog = data;
488         struct desktop *desktop = dialog->desktop;
489
490         if (button == BTN_LEFT) {
491                 if (state == 0 && !dialog->closing) {
492                         display_defer(desktop->display, &desktop->unlock_task);
493                         dialog->closing = 1;
494                 }
495         }
496 }
497
498 static void
499 unlock_dialog_keyboard_focus_handler(struct window *window,
500                                      struct input *device, void *data)
501 {
502         window_schedule_redraw(window);
503 }
504
505 static int
506 unlock_dialog_widget_enter_handler(struct widget *widget,
507                                    struct input *input,
508                                    float x, float y, void *data)
509 {
510         struct unlock_dialog *dialog = data;
511
512         dialog->button_focused = 1;
513         widget_schedule_redraw(widget);
514
515         return WL_CURSOR_LEFT_PTR;
516 }
517
518 static void
519 unlock_dialog_widget_leave_handler(struct widget *widget,
520                                    struct input *input, void *data)
521 {
522         struct unlock_dialog *dialog = data;
523
524         dialog->button_focused = 0;
525         widget_schedule_redraw(widget);
526 }
527
528 static struct unlock_dialog *
529 unlock_dialog_create(struct desktop *desktop)
530 {
531         struct display *display = desktop->display;
532         struct unlock_dialog *dialog;
533
534         dialog = malloc(sizeof *dialog);
535         if (!dialog)
536                 return NULL;
537         memset(dialog, 0, sizeof *dialog);
538
539         dialog->window = window_create(display);
540         dialog->widget = frame_create(dialog->window, dialog);
541         window_set_title(dialog->window, "Unlock your desktop");
542         window_set_custom(dialog->window);
543
544         window_set_user_data(dialog->window, dialog);
545         window_set_keyboard_focus_handler(dialog->window,
546                                           unlock_dialog_keyboard_focus_handler);
547         dialog->button = widget_add_widget(dialog->widget, dialog);
548         widget_set_redraw_handler(dialog->widget,
549                                   unlock_dialog_redraw_handler);
550         widget_set_enter_handler(dialog->button,
551                                  unlock_dialog_widget_enter_handler);
552         widget_set_leave_handler(dialog->button,
553                                  unlock_dialog_widget_leave_handler);
554         widget_set_button_handler(dialog->button,
555                                   unlock_dialog_button_handler);
556
557         desktop_shell_set_lock_surface(desktop->shell,
558                window_get_wl_shell_surface(dialog->window));
559
560         window_schedule_resize(dialog->window, 260, 230);
561
562         return dialog;
563 }
564
565 static void
566 unlock_dialog_destroy(struct unlock_dialog *dialog)
567 {
568         window_destroy(dialog->window);
569         free(dialog);
570 }
571
572 static void
573 unlock_dialog_finish(struct task *task, uint32_t events)
574 {
575         struct desktop *desktop =
576                 container_of(task, struct desktop, unlock_task);
577
578         desktop_shell_unlock(desktop->shell);
579         unlock_dialog_destroy(desktop->unlock_dialog);
580         desktop->unlock_dialog = NULL;
581 }
582
583 static void
584 desktop_shell_configure(void *data,
585                         struct desktop_shell *desktop_shell,
586                         uint32_t edges,
587                         struct wl_shell_surface *shell_surface,
588                         int32_t width, int32_t height)
589 {
590         struct window *window = wl_shell_surface_get_user_data(shell_surface);
591         struct surface *s = window_get_user_data(window);
592
593         s->configure(data, desktop_shell, edges, window, width, height);
594 }
595
596 static void
597 desktop_shell_prepare_lock_surface(void *data,
598                                    struct desktop_shell *desktop_shell)
599 {
600         struct desktop *desktop = data;
601
602         if (!key_locking) {
603                 desktop_shell_unlock(desktop->shell);
604                 return;
605         }
606
607         if (!desktop->unlock_dialog) {
608                 desktop->unlock_dialog = unlock_dialog_create(desktop);
609                 desktop->unlock_dialog->desktop = desktop;
610         }
611 }
612
613 static const struct desktop_shell_listener listener = {
614         desktop_shell_configure,
615         desktop_shell_prepare_lock_surface
616 };
617
618 static struct background *
619 background_create(struct desktop *desktop)
620 {
621         struct background *background;
622
623         background = malloc(sizeof *background);
624         memset(background, 0, sizeof *background);
625
626         background->base.configure = background_configure;
627         background->window = window_create(desktop->display);
628         background->widget = window_add_widget(background->window, background);
629         window_set_custom(background->window);
630         window_set_user_data(background->window, background);
631         widget_set_redraw_handler(background->widget, background_draw);
632
633         return background;
634 }
635
636 static void
637 create_output(struct desktop *desktop, uint32_t id)
638 {
639         struct output *output;
640
641         output = calloc(1, sizeof *output);
642         if (!output)
643                 return;
644
645         output->output = wl_display_bind(display_get_display(desktop->display),
646                                          id, &wl_output_interface);
647
648         wl_list_insert(&desktop->outputs, &output->link);
649 }
650
651 static void
652 global_handler(struct wl_display *display, uint32_t id,
653                const char *interface, uint32_t version, void *data)
654 {
655         struct desktop *desktop = data;
656
657         if (!strcmp(interface, "desktop_shell")) {
658                 desktop->shell =
659                         wl_display_bind(display, id, &desktop_shell_interface);
660                 desktop_shell_add_listener(desktop->shell, &listener, desktop);
661         } else if (!strcmp(interface, "wl_output")) {
662                 create_output(desktop, id);
663         }
664 }
665
666 static void
667 launcher_section_done(void *data)
668 {
669         struct desktop *desktop = data;
670         struct output *output;
671
672         if (key_launcher_icon == NULL || key_launcher_path == NULL) {
673                 fprintf(stderr, "invalid launcher section\n");
674                 return;
675         }
676
677         wl_list_for_each(output, &desktop->outputs, link)
678                 panel_add_launcher(output->panel,
679                                    key_launcher_icon, key_launcher_path);
680
681         free(key_launcher_icon);
682         key_launcher_icon = NULL;
683         free(key_launcher_path);
684         key_launcher_path = NULL;
685 }
686
687 static void
688 add_default_launcher(struct desktop *desktop)
689 {
690         struct output *output;
691
692         wl_list_for_each(output, &desktop->outputs, link)
693                 panel_add_launcher(output->panel,
694                                    DATADIR "/weston/terminal.png",
695                                    BINDIR "/weston-terminal");
696 }
697
698 int main(int argc, char *argv[])
699 {
700         struct desktop desktop = { 0 };
701         char *config_file;
702         struct output *output;
703         int ret;
704
705         desktop.unlock_task.run = unlock_dialog_finish;
706         wl_list_init(&desktop.outputs);
707
708         desktop.display = display_create(argc, argv);
709         if (desktop.display == NULL) {
710                 fprintf(stderr, "failed to create display: %m\n");
711                 return -1;
712         }
713
714         wl_display_add_global_listener(display_get_display(desktop.display),
715                                        global_handler, &desktop);
716
717         wl_list_for_each(output, &desktop.outputs, link) {
718                 struct wl_shell_surface *s;
719
720                 output->panel = panel_create(desktop.display);
721                 s = window_get_wl_shell_surface(output->panel->window);
722                 desktop_shell_set_panel(desktop.shell, output->output, s);
723
724                 output->background = background_create(&desktop);
725                 s = window_get_wl_shell_surface(output->background->window);
726                 desktop_shell_set_background(desktop.shell, output->output, s);
727         }
728
729         config_file = config_file_path("weston.ini");
730         ret = parse_config_file(config_file,
731                                 config_sections, ARRAY_LENGTH(config_sections),
732                                 &desktop);
733         free(config_file);
734         if (ret < 0)
735                 add_default_launcher(&desktop);
736
737         signal(SIGCHLD, sigchild_handler);
738
739         display_run(desktop.display);
740
741         return 0;
742 }