button-test: Use wl_display_roundtrip instead of yield()
[profile/ivi/weston.git] / clients / tablet-shell.c
1 /*
2  * Copyright © 2011, 2012 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/wait.h>
29
30 #include "window.h"
31 #include "../shared/cairo-util.h"
32 #include "../shared/config-parser.h"
33
34 #include "tablet-shell-client-protocol.h"
35
36 struct tablet {
37         struct display *display;
38         struct tablet_shell *tablet_shell;
39         struct rectangle allocation;
40         struct window *switcher;
41
42         struct homescreen *homescreen;
43         struct lockscreen *lockscreen;
44 };
45
46 struct homescreen {
47         struct window *window;
48         struct widget *widget;
49         struct wl_list launcher_list;
50 };
51
52 struct lockscreen {
53         struct window *window;
54         struct widget *widget;
55 };
56
57 struct launcher {
58         struct widget *widget;
59         struct homescreen *homescreen;
60         cairo_surface_t *icon;
61         int focused, pressed;
62         char *path;
63         struct wl_list link;
64 };
65
66 static char *key_lockscreen_icon;
67 static char *key_lockscreen_background;
68 static char *key_homescreen_background;
69 static char *key_launcher_icon;
70 static char *key_launcher_path;
71 static void launcher_section_done(void *data);
72
73 static const struct config_key shell_config_keys[] = {
74         { "lockscreen-icon", CONFIG_KEY_STRING, &key_lockscreen_icon },
75         { "lockscreen", CONFIG_KEY_STRING, &key_lockscreen_background },
76         { "homescreen", CONFIG_KEY_STRING, &key_homescreen_background },
77 };
78
79 static const struct config_key launcher_config_keys[] = {
80         { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
81         { "path", CONFIG_KEY_STRING, &key_launcher_path },
82 };
83
84 static const struct config_section config_sections[] = {
85         { "shell",
86           shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
87         { "launcher",
88           launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
89           launcher_section_done }
90 };
91
92 static void
93 sigchild_handler(int s)
94 {
95         int status;
96         pid_t pid;
97
98         while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
99                 fprintf(stderr, "child %d exited\n", pid);
100 }
101
102 static void
103 paint_background(cairo_t *cr, const char *path, struct rectangle *allocation)
104 {
105         cairo_surface_t *image = NULL;
106         cairo_pattern_t *pattern;
107         cairo_matrix_t matrix;
108         double sx, sy;
109
110         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
111         if (path)
112                 image = load_cairo_surface(path);
113         if (image) {
114                 pattern = cairo_pattern_create_for_surface(image);
115                 sx = (double) cairo_image_surface_get_width(image) /
116                         allocation->width;
117                 sy = (double) cairo_image_surface_get_height(image) /
118                         allocation->height;
119                 cairo_matrix_init_scale(&matrix, sx, sy);
120                 cairo_pattern_set_matrix(pattern, &matrix);
121                 cairo_set_source(cr, pattern);
122                 cairo_pattern_destroy (pattern);
123                 cairo_surface_destroy(image);
124                 cairo_paint(cr);
125         } else {
126                 fprintf(stderr, "couldn't load background image: %s\n", path);
127                 cairo_set_source_rgb(cr, 0.2, 0, 0);
128                 cairo_paint(cr);
129         }
130 }
131
132 static void
133 homescreen_draw(struct widget *widget, void *data)
134 {
135         struct homescreen *homescreen = data;
136         cairo_surface_t *surface;
137         struct rectangle allocation;
138         cairo_t *cr;
139         struct launcher *launcher;
140         const int rows = 4, columns = 5, icon_width = 128, icon_height = 128;
141         int x, y, i, width, height, vmargin, hmargin, vpadding, hpadding;
142
143         surface = window_get_surface(homescreen->window);
144         cr = cairo_create(surface);
145
146         widget_get_allocation(widget, &allocation);
147         paint_background(cr, key_homescreen_background, &allocation);
148
149         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
150
151         width = allocation.width - columns * icon_width;
152         hpadding = width / (columns + 1);
153         hmargin = (width - hpadding * (columns - 1)) / 2;
154
155         height = allocation.height - rows * icon_height;
156         vpadding = height / (rows + 1);
157         vmargin = (height - vpadding * (rows - 1)) / 2;
158
159         x = hmargin;
160         y = vmargin;
161         i = 0;
162
163         wl_list_for_each(launcher, &homescreen->launcher_list, link) {
164                 widget_set_allocation(launcher->widget,
165                                       x, y, icon_width, icon_height);
166                 x += icon_width + hpadding;
167                 i++;
168                 if (i == columns) {
169                         x = hmargin;
170                         y += icon_height + vpadding;
171                         i = 0;
172                 }
173         }
174
175         cairo_destroy(cr);
176         cairo_surface_destroy(surface);
177 }
178
179 static void
180 lockscreen_draw(struct widget *widget, void *data)
181 {
182         struct lockscreen *lockscreen = data;
183         cairo_surface_t *surface;
184         cairo_surface_t *icon;
185         struct rectangle allocation;
186         cairo_t *cr;
187         int width, height;
188
189         surface = window_get_surface(lockscreen->window);
190         cr = cairo_create(surface);
191
192         widget_get_allocation(widget, &allocation);
193         paint_background(cr, key_lockscreen_background, &allocation);
194
195         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
196         icon = load_cairo_surface(key_lockscreen_icon);
197         if (icon) {
198                 width = cairo_image_surface_get_width(icon);
199                 height = cairo_image_surface_get_height(icon);
200                 cairo_set_source_surface(cr, icon,
201                         allocation.x + (allocation.width - width) / 2,
202                         allocation.y + (allocation.height - height) / 2);
203         } else {
204                 fprintf(stderr, "couldn't load lockscreen icon: %s\n",
205                                  key_lockscreen_icon);
206                 cairo_set_source_rgb(cr, 0.2, 0, 0);
207         }
208         cairo_paint(cr);
209         cairo_destroy(cr);
210         cairo_surface_destroy(icon);
211         cairo_surface_destroy(surface);
212 }
213
214 static void
215 lockscreen_button_handler(struct widget *widget,
216                           struct input *input, uint32_t time,
217                           uint32_t button,
218                           enum wl_pointer_button_state state, void *data)
219 {
220         struct lockscreen *lockscreen = data;
221
222         if (state == WL_POINTER_BUTTON_STATE_PRESSED && lockscreen->window) {
223                 window_destroy(lockscreen->window);
224                 lockscreen->window = NULL;
225         }
226 }
227
228 static struct homescreen *
229 homescreen_create(struct tablet *tablet)
230 {
231         struct homescreen *homescreen;
232
233         homescreen = malloc (sizeof *homescreen);
234         memset(homescreen, 0, sizeof *homescreen);
235
236         homescreen->window = window_create_custom(tablet->display);
237         homescreen->widget =
238                 window_add_widget(homescreen->window, homescreen);
239         window_set_user_data(homescreen->window, homescreen);
240         window_set_title(homescreen->window, "homescreen");
241         widget_set_redraw_handler(homescreen->widget, homescreen_draw);
242
243         return homescreen;
244 }
245
246 static struct lockscreen *
247 lockscreen_create(struct tablet *tablet)
248 {
249         struct lockscreen *lockscreen;
250
251         lockscreen = malloc (sizeof *lockscreen);
252         memset(lockscreen, 0, sizeof *lockscreen);
253
254         lockscreen->window = window_create_custom(tablet->display);
255         lockscreen->widget =
256                 window_add_widget(lockscreen->window, lockscreen);
257         window_set_user_data(lockscreen->window, lockscreen);
258         window_set_title(lockscreen->window, "lockscreen");
259         widget_set_redraw_handler(lockscreen->widget, lockscreen_draw);
260         widget_set_button_handler(lockscreen->widget,
261                                   lockscreen_button_handler);
262
263         return lockscreen;
264 }
265
266 static void
267 show_lockscreen(void *data, struct tablet_shell *tablet_shell)
268 {
269         struct tablet *tablet = data;
270
271         tablet->lockscreen = lockscreen_create(tablet);
272         tablet_shell_set_lockscreen(tablet->tablet_shell,
273                         window_get_wl_surface(tablet->lockscreen->window));
274
275         widget_schedule_resize(tablet->lockscreen->widget,
276                                tablet->allocation.width,
277                                tablet->allocation.height);
278 }
279
280 static void
281 show_switcher(void *data, struct tablet_shell *tablet_shell)
282 {
283         struct tablet *tablet = data;
284
285         tablet->switcher = window_create_custom(tablet->display);
286         window_set_user_data(tablet->switcher, tablet);
287         tablet_shell_set_switcher(tablet->tablet_shell,
288                                   window_get_wl_surface(tablet->switcher));
289 }
290
291 static void
292 hide_switcher(void *data, struct tablet_shell *tablet_shell)
293 {
294 }
295
296 static const struct tablet_shell_listener tablet_shell_listener = {
297         show_lockscreen,
298         show_switcher,
299         hide_switcher
300 };
301
302 static int
303 launcher_enter_handler(struct widget *widget, struct input *input,
304                              float x, float y, void *data)
305 {
306         struct launcher *launcher = data;
307
308         launcher->focused = 1;
309         widget_schedule_redraw(widget);
310
311         return CURSOR_LEFT_PTR;
312 }
313
314 static void
315 launcher_leave_handler(struct widget *widget,
316                              struct input *input, void *data)
317 {
318         struct launcher *launcher = data;
319
320         launcher->focused = 0;
321         widget_schedule_redraw(widget);
322 }
323
324 static void
325 launcher_activate(struct launcher *widget)
326 {
327         pid_t pid;
328
329         pid = fork();
330         if (pid < 0) {
331                 fprintf(stderr, "fork failed: %m\n");
332                 return;
333         }
334
335         if (pid)
336                 return;
337
338         if (execl(widget->path, widget->path, NULL) < 0) {
339                 fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
340                 exit(1);
341         }
342 }
343
344 static void
345 launcher_button_handler(struct widget *widget,
346                               struct input *input, uint32_t time,
347                               uint32_t button,
348                               enum wl_pointer_button_state state, void *data)
349 {
350         struct launcher *launcher;
351
352         launcher = widget_get_user_data(widget);
353         widget_schedule_redraw(widget);
354         if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
355                 launcher_activate(launcher);
356                 launcher->pressed = 0;
357         } else if (state == WL_POINTER_BUTTON_STATE_PRESSED) 
358                 launcher->pressed = 1;
359 }
360
361 static void
362 launcher_redraw_handler(struct widget *widget, void *data)
363 {
364         struct launcher *launcher = data;
365         cairo_surface_t *surface;
366         struct rectangle allocation;
367         cairo_t *cr;
368
369         surface = window_get_surface(launcher->homescreen->window);
370         cr = cairo_create(surface);
371
372         widget_get_allocation(widget, &allocation);
373         if (launcher->pressed) {
374                 allocation.x++;
375                 allocation.y++;
376         }
377
378         cairo_set_source_surface(cr, launcher->icon,
379                                  allocation.x, allocation.y);
380         cairo_paint(cr);
381
382         if (launcher->focused) {
383                 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
384                 cairo_mask_surface(cr, launcher->icon,
385                                    allocation.x, allocation.y);
386         }
387
388         cairo_destroy(cr);
389 }
390
391 static void
392 tablet_shell_add_launcher(struct tablet *tablet,
393                           const char *icon, const char *path)
394 {
395         struct launcher *launcher;
396         struct homescreen *homescreen = tablet->homescreen;
397
398         launcher = malloc(sizeof *launcher);
399         launcher->path = strdup(path);
400         launcher->icon = load_cairo_surface(icon);
401         if ( !launcher->icon ||
402              cairo_surface_status (launcher->icon) != CAIRO_STATUS_SUCCESS) {
403                 fprintf(stderr, "couldn't load %s\n", icon);
404                 free(launcher);
405                 return;
406         }
407
408         launcher->homescreen = homescreen;
409         launcher->widget = widget_add_widget(homescreen->widget, launcher);
410         widget_set_enter_handler(launcher->widget,
411                                  launcher_enter_handler);
412         widget_set_leave_handler(launcher->widget,
413                                  launcher_leave_handler);
414         widget_set_button_handler(launcher->widget,
415                                   launcher_button_handler);
416         widget_set_redraw_handler(launcher->widget,
417                                   launcher_redraw_handler);
418
419         wl_list_insert(&homescreen->launcher_list, &launcher->link);
420 }
421
422 static void
423 launcher_section_done(void *data)
424 {
425         struct tablet *tablet = data;
426
427         if (key_launcher_icon == NULL || key_launcher_path == NULL) {
428                 fprintf(stderr, "invalid launcher section\n");
429                 return;
430         }
431
432         tablet_shell_add_launcher(tablet, key_launcher_icon, key_launcher_path);
433
434         free(key_launcher_icon);
435         key_launcher_icon = NULL;
436         free(key_launcher_path);
437         key_launcher_path = NULL;
438 }
439
440 static void
441 global_handler(struct display *display, uint32_t name,
442                 const char *interface, uint32_t version, void *data)
443 {
444         struct tablet *tablet = data;
445
446         if (!strcmp(interface, "tablet_shell")) {
447                 tablet->tablet_shell =
448                         display_bind(display, name,
449                                      &tablet_shell_interface, 1);
450                 tablet_shell_add_listener(tablet->tablet_shell,
451                                 &tablet_shell_listener, tablet);
452         }
453 }
454
455 int main(int argc, char *argv[])
456 {
457         struct tablet tablet = { 0 };
458         struct display *display;
459         char *config_file;
460         struct output *output;
461
462         display = display_create(argc, argv);
463         if (display == NULL) {
464                 fprintf(stderr, "failed to create display: %m\n");
465                 return -1;
466         }
467
468         tablet.display = display;
469
470         display_set_user_data(tablet.display, &tablet);
471         display_set_global_handler(tablet.display, global_handler);
472
473         tablet.homescreen = homescreen_create(&tablet);
474         tablet_shell_set_homescreen(tablet.tablet_shell,
475                         window_get_wl_surface(tablet.homescreen->window));
476         wl_list_init(&tablet.homescreen->launcher_list);
477
478         config_file = config_file_path("weston.ini");
479         parse_config_file(config_file,
480                           config_sections, ARRAY_LENGTH(config_sections),
481                           &tablet);
482         free(config_file);
483
484         signal(SIGCHLD, sigchild_handler);
485
486         output = display_get_output(tablet.display);
487         output_get_allocation(output, &tablet.allocation);
488         widget_schedule_resize(tablet.homescreen->widget,
489                         tablet.allocation.width,
490                         tablet.allocation.height);
491         display_run(display);
492
493         return 0;
494 }