window: Dont take width and height in window constructor
[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 "cairo-util.h"
37 #include "window.h"
38 #include "../shared/config-parser.h"
39
40 #include "desktop-shell-client-protocol.h"
41
42 struct desktop {
43         struct display *display;
44         struct desktop_shell *shell;
45         struct unlock_dialog *unlock_dialog;
46         struct task unlock_task;
47         struct wl_list outputs;
48 };
49
50 struct surface {
51         void (*configure)(void *data,
52                           struct desktop_shell *desktop_shell,
53                           uint32_t time, uint32_t edges,
54                           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         { "desktop-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                              uint32_t time, int32_t x, int32_t y, void *data)
238 {
239         struct panel_launcher *launcher = data;
240
241         launcher->focused = 1;
242         widget_schedule_redraw(widget);
243
244         return POINTER_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                               int button, int 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                      int button, int 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 time, uint32_t edges,
304                 struct window *window,
305                 int32_t width, int32_t height)
306 {
307         struct surface *surface = window_get_user_data(window);
308         struct panel *panel = container_of(surface, struct panel, base);
309
310         window_schedule_resize(panel->window, width, 32);
311 }
312
313 static struct panel *
314 panel_create(struct display *display)
315 {
316         struct panel *panel;
317
318         panel = malloc(sizeof *panel);
319         memset(panel, 0, sizeof *panel);
320
321         panel->base.configure = panel_configure;
322         panel->window = window_create(display);
323         panel->widget = window_add_widget(panel->window, panel);
324         wl_list_init(&panel->launcher_list);
325
326         window_set_title(panel->window, "panel");
327         window_set_custom(panel->window);
328         window_set_user_data(panel->window, panel);
329
330         widget_set_redraw_handler(panel->widget, panel_redraw_handler);
331         widget_set_resize_handler(panel->widget, panel_resize_handler);
332         widget_set_button_handler(panel->widget, panel_button_handler);
333
334         return panel;
335 }
336
337 static void
338 panel_add_launcher(struct panel *panel, const char *icon, const char *path)
339 {
340         struct panel_launcher *launcher;
341
342         launcher = malloc(sizeof *launcher);
343         memset(launcher, 0, sizeof *launcher);
344         launcher->icon = cairo_image_surface_create_from_png(icon);
345         launcher->path = strdup(path);
346         launcher->panel = panel;
347         wl_list_insert(panel->launcher_list.prev, &launcher->link);
348
349         launcher->widget = widget_add_widget(panel->widget, launcher);
350         widget_set_enter_handler(launcher->widget,
351                                  panel_launcher_enter_handler);
352         widget_set_leave_handler(launcher->widget,
353                                    panel_launcher_leave_handler);
354         widget_set_button_handler(launcher->widget,
355                                     panel_launcher_button_handler);
356         widget_set_redraw_handler(launcher->widget,
357                                   panel_launcher_redraw_handler);
358 }
359
360 enum {
361         BACKGROUND_SCALE,
362         BACKGROUND_TILE
363 };
364
365 static void
366 background_draw(struct widget *widget, void *data)
367 {
368         struct background *background = data;
369         cairo_surface_t *surface, *image;
370         cairo_pattern_t *pattern;
371         cairo_matrix_t matrix;
372         cairo_t *cr;
373         double sx, sy;
374         struct rectangle allocation;
375         int type = -1;
376
377         surface = window_get_surface(background->window);
378
379         cr = cairo_create(surface);
380         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
381         cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
382         cairo_paint(cr);
383
384         widget_get_allocation(widget, &allocation);
385         image = NULL;
386         if (key_background_image)
387                 image = load_image(key_background_image);
388
389         if (strcmp(key_background_type, "scale") == 0)
390                 type = BACKGROUND_SCALE;
391         else if (strcmp(key_background_type, "tile") == 0)
392                 type = BACKGROUND_TILE;
393         else
394                 fprintf(stderr, "invalid background-type: %s\n",
395                         key_background_type);
396
397         if (image && type != -1) {
398                 pattern = cairo_pattern_create_for_surface(image);
399                 switch (type) {
400                 case BACKGROUND_SCALE:
401                         sx = (double) cairo_image_surface_get_width(image) /
402                                 allocation.width;
403                         sy = (double) cairo_image_surface_get_height(image) /
404                                 allocation.height;
405                         cairo_matrix_init_scale(&matrix, sx, sy);
406                         cairo_pattern_set_matrix(pattern, &matrix);
407                         break;
408                 case BACKGROUND_TILE:
409                         cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
410                         break;
411                 }
412                 cairo_set_source(cr, pattern);
413                 cairo_pattern_destroy (pattern);
414                 cairo_surface_destroy(image);
415         } else {
416                 set_hex_color(cr, key_background_color);
417         }
418
419         cairo_paint(cr);
420         cairo_destroy(cr);
421         cairo_surface_destroy(surface);
422 }
423
424 static void
425 background_configure(void *data,
426                      struct desktop_shell *desktop_shell,
427                      uint32_t time, uint32_t edges,
428                      struct window *window,
429                      int32_t width, int32_t height)
430 {
431         struct background *background =
432                 (struct background *) window_get_user_data(window);
433
434         widget_schedule_resize(background->widget, width, height);
435 }
436
437 static void
438 unlock_dialog_redraw_handler(struct widget *widget, void *data)
439 {
440         struct unlock_dialog *dialog = data;
441         struct rectangle allocation;
442         cairo_t *cr;
443         cairo_surface_t *surface;
444         cairo_pattern_t *pat;
445         double cx, cy, r, f;
446
447         surface = window_get_surface(dialog->window);
448         cr = cairo_create(surface);
449         widget_get_allocation(dialog->widget, &allocation);
450         cairo_rectangle(cr, allocation.x, allocation.y,
451                         allocation.width, allocation.height);
452         cairo_clip(cr);
453         cairo_push_group(cr);
454         cairo_translate(cr, allocation.x, allocation.y);
455
456         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
457         cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
458         cairo_paint(cr);
459
460         if (dialog->button_focused)
461                 f = 1.0;
462         else
463                 f = 0.7;
464
465         cx = allocation.width / 2.0;
466         cy = allocation.height / 2.0;
467         r = (cx < cy ? cx : cy) * 0.4;
468         pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
469         cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
470         cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
471         cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
472         cairo_set_source(cr, pat);
473         cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
474         cairo_fill(cr);
475
476         widget_set_allocation(dialog->button,
477                             allocation.x + cx - r,
478                             allocation.y + cy - r, 2 * r, 2 * r);
479         cairo_pattern_destroy(pat);
480
481         cairo_pop_group_to_source(cr);
482         cairo_paint(cr);
483         cairo_destroy(cr);
484
485         cairo_surface_destroy(surface);
486 }
487
488 static void
489 unlock_dialog_button_handler(struct widget *widget,
490                              struct input *input, uint32_t time,
491                              int button, int state, void *data)
492 {
493         struct unlock_dialog *dialog = data;
494         struct desktop *desktop = dialog->desktop;
495
496         if (button == BTN_LEFT) {
497                 if (state == 0 && !dialog->closing) {
498                         display_defer(desktop->display, &desktop->unlock_task);
499                         dialog->closing = 1;
500                 }
501         }
502 }
503
504 static void
505 unlock_dialog_keyboard_focus_handler(struct window *window,
506                                      struct input *device, void *data)
507 {
508         window_schedule_redraw(window);
509 }
510
511 static int
512 unlock_dialog_widget_enter_handler(struct widget *widget,
513                                    struct input *input, uint32_t time,
514                                    int32_t x, int32_t y, void *data)
515 {
516         struct unlock_dialog *dialog = data;
517
518         dialog->button_focused = 1;
519         widget_schedule_redraw(widget);
520
521         return POINTER_LEFT_PTR;
522 }
523
524 static void
525 unlock_dialog_widget_leave_handler(struct widget *widget,
526                                    struct input *input, void *data)
527 {
528         struct unlock_dialog *dialog = data;
529
530         dialog->button_focused = 0;
531         widget_schedule_redraw(widget);
532 }
533
534 static struct unlock_dialog *
535 unlock_dialog_create(struct desktop *desktop)
536 {
537         struct display *display = desktop->display;
538         struct unlock_dialog *dialog;
539
540         dialog = malloc(sizeof *dialog);
541         if (!dialog)
542                 return NULL;
543         memset(dialog, 0, sizeof *dialog);
544
545         dialog->window = window_create(display);
546         dialog->widget = frame_create(dialog->window, dialog);
547         window_set_title(dialog->window, "Unlock your desktop");
548         window_set_custom(dialog->window);
549
550         window_set_user_data(dialog->window, dialog);
551         window_set_keyboard_focus_handler(dialog->window,
552                                           unlock_dialog_keyboard_focus_handler);
553         dialog->button = widget_add_widget(dialog->widget, dialog);
554         widget_set_redraw_handler(dialog->widget,
555                                   unlock_dialog_redraw_handler);
556         widget_set_enter_handler(dialog->button,
557                                  unlock_dialog_widget_enter_handler);
558         widget_set_leave_handler(dialog->button,
559                                  unlock_dialog_widget_leave_handler);
560         widget_set_button_handler(dialog->button,
561                                   unlock_dialog_button_handler);
562
563         desktop_shell_set_lock_surface(desktop->shell,
564                window_get_wl_shell_surface(dialog->window));
565
566         window_schedule_resize(dialog->window, 260, 230);
567
568         return dialog;
569 }
570
571 static void
572 unlock_dialog_destroy(struct unlock_dialog *dialog)
573 {
574         window_destroy(dialog->window);
575         free(dialog);
576 }
577
578 static void
579 unlock_dialog_finish(struct task *task, uint32_t events)
580 {
581         struct desktop *desktop =
582                 container_of(task, struct desktop, unlock_task);
583
584         desktop_shell_unlock(desktop->shell);
585         unlock_dialog_destroy(desktop->unlock_dialog);
586         desktop->unlock_dialog = NULL;
587 }
588
589 static void
590 desktop_shell_configure(void *data,
591                         struct desktop_shell *desktop_shell,
592                         uint32_t time, uint32_t edges,
593                         struct wl_shell_surface *shell_surface,
594                         int32_t width, int32_t height)
595 {
596         struct window *window = wl_shell_surface_get_user_data(shell_surface);
597         struct surface *s = window_get_user_data(window);
598
599         s->configure(data, desktop_shell, time, edges, window, width, height);
600 }
601
602 static void
603 desktop_shell_prepare_lock_surface(void *data,
604                                    struct desktop_shell *desktop_shell)
605 {
606         struct desktop *desktop = data;
607
608         if (!key_locking) {
609                 desktop_shell_unlock(desktop->shell);
610                 return;
611         }
612
613         if (!desktop->unlock_dialog) {
614                 desktop->unlock_dialog = unlock_dialog_create(desktop);
615                 desktop->unlock_dialog->desktop = desktop;
616         }
617 }
618
619 static const struct desktop_shell_listener listener = {
620         desktop_shell_configure,
621         desktop_shell_prepare_lock_surface
622 };
623
624 static struct background *
625 background_create(struct desktop *desktop)
626 {
627         struct background *background;
628
629         background = malloc(sizeof *background);
630         memset(background, 0, sizeof *background);
631
632         background->base.configure = background_configure;
633         background->window = window_create(desktop->display);
634         background->widget = window_add_widget(background->window, background);
635         window_set_custom(background->window);
636         window_set_user_data(background->window, background);
637         widget_set_redraw_handler(background->widget, background_draw);
638
639         return background;
640 }
641
642 static void
643 create_output(struct desktop *desktop, uint32_t id)
644 {
645         struct output *output;
646
647         output = calloc(1, sizeof *output);
648         if (!output)
649                 return;
650
651         output->output = wl_display_bind(display_get_display(desktop->display),
652                                          id, &wl_output_interface);
653
654         wl_list_insert(&desktop->outputs, &output->link);
655 }
656
657 static void
658 global_handler(struct wl_display *display, uint32_t id,
659                const char *interface, uint32_t version, void *data)
660 {
661         struct desktop *desktop = data;
662
663         if (!strcmp(interface, "desktop_shell")) {
664                 desktop->shell =
665                         wl_display_bind(display, id, &desktop_shell_interface);
666                 desktop_shell_add_listener(desktop->shell, &listener, desktop);
667         } else if (!strcmp(interface, "wl_output")) {
668                 create_output(desktop, id);
669         }
670 }
671
672 static void
673 launcher_section_done(void *data)
674 {
675         struct desktop *desktop = data;
676         struct output *output;
677
678         if (key_launcher_icon == NULL || key_launcher_path == NULL) {
679                 fprintf(stderr, "invalid launcher section\n");
680                 return;
681         }
682
683         wl_list_for_each(output, &desktop->outputs, link)
684                 panel_add_launcher(output->panel,
685                                    key_launcher_icon, key_launcher_path);
686
687         free(key_launcher_icon);
688         key_launcher_icon = NULL;
689         free(key_launcher_path);
690         key_launcher_path = NULL;
691 }
692
693 static void
694 add_default_launcher(struct desktop *desktop)
695 {
696         struct output *output;
697
698         wl_list_for_each(output, &desktop->outputs, link)
699                 panel_add_launcher(output->panel,
700                                    DATADIR "/weston/terminal.png",
701                                    "/usr/bin/weston-terminal");
702 }
703
704 int main(int argc, char *argv[])
705 {
706         struct desktop desktop = { 0 };
707         char *config_file;
708         struct output *output;
709         int ret;
710
711         desktop.unlock_task.run = unlock_dialog_finish;
712         wl_list_init(&desktop.outputs);
713
714         desktop.display = display_create(&argc, &argv, NULL);
715         if (desktop.display == NULL) {
716                 fprintf(stderr, "failed to create display: %m\n");
717                 return -1;
718         }
719
720         wl_display_add_global_listener(display_get_display(desktop.display),
721                                        global_handler, &desktop);
722
723         wl_list_for_each(output, &desktop.outputs, link) {
724                 struct wl_shell_surface *s;
725
726                 output->panel = panel_create(desktop.display);
727                 s = window_get_wl_shell_surface(output->panel->window);
728                 desktop_shell_set_panel(desktop.shell, output->output, s);
729
730                 output->background = background_create(&desktop);
731                 s = window_get_wl_shell_surface(output->background->window);
732                 desktop_shell_set_background(desktop.shell, output->output, s);
733         }
734
735         config_file = config_file_path("weston-desktop-shell.ini");
736         ret = parse_config_file(config_file,
737                                 config_sections, ARRAY_LENGTH(config_sections),
738                                 &desktop);
739         free(config_file);
740         if (ret < 0)
741                 add_default_launcher(&desktop);
742
743         signal(SIGCHLD, sigchild_handler);
744
745         display_run(desktop.display);
746
747         return 0;
748 }