cairo-util: Add helper to load jpeg files
[profile/ivi/weston-ivi-shell.git] / clients / desktop-shell.c
1 /*
2  * Copyright © 2011 Kristian Høgsberg
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 <fcntl.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <cairo.h>
31 #include <sys/wait.h>
32 #include <linux/input.h>
33
34 #include "wayland-client.h"
35 #include "cairo-util.h"
36 #include "window.h"
37
38 #include <desktop-shell-client-protocol.h>
39
40 struct desktop {
41         struct display *display;
42         struct desktop_shell *shell;
43         struct panel *panel;
44         struct window *background;
45         const char *background_path;
46 };
47
48 struct panel {
49         struct window *window;
50         struct window *menu;
51 };
52
53 struct panel_item {
54         struct item *item;
55         struct panel *panel;
56         cairo_surface_t *icon;
57         int pressed;
58         const char *path;
59 };
60
61 static void
62 sigchild_handler(int s)
63 {
64         int status;
65         pid_t pid;
66
67         while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
68                 fprintf(stderr, "child %d exited\n", pid);
69 }
70
71 static void
72 show_menu(struct panel *panel, struct input *input)
73 {
74         int32_t x, y, width = 200, height = 200;
75         struct display *display;
76
77         input_get_position(input, &x, &y);
78         display = window_get_display(panel->window);
79         panel->menu = window_create_transient(display, panel->window,
80                                               x - 10, y - 10, width, height);
81
82         window_draw(panel->menu);
83         window_flush(panel->menu);
84 }
85
86 static void
87 panel_activate_item(struct panel *panel, struct panel_item *item)
88 {
89         pid_t pid;
90
91         pid = fork();
92         if (pid < 0) {
93                 fprintf(stderr, "fork failed: %m\n");
94                 return;
95         }
96
97         if (pid)
98                 return;
99         
100         if (execl(item->path, item->path, NULL) < 0) {
101                 fprintf(stderr, "execl failed: %m\n");
102                 exit(1);
103         }
104 }
105
106 static void
107 panel_draw_item(struct item *item, void *data)
108 {
109         cairo_t *cr = data;
110         struct panel_item *pi;
111         int x, y, width, height;
112         double dx, dy;
113
114         pi = item_get_user_data(item);
115         width = cairo_image_surface_get_width(pi->icon);
116         height = cairo_image_surface_get_height(pi->icon);
117         x = 0;
118         y = -height / 2;
119         if (pi->pressed) {
120                 x++;
121                 y++;
122         }
123
124         dx = x;
125         dy = y;
126         cairo_user_to_device(cr, &dx, &dy);
127         item_set_allocation(item, dx, dy, width, height);
128
129         cairo_set_source_surface(cr, pi->icon, x, y);
130         cairo_paint(cr);
131
132         if (window_get_focus_item(pi->panel->window) == item) {
133                 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
134                 cairo_mask_surface(cr, pi->icon, x, y);
135         }
136
137         cairo_translate(cr, width + 10, 0);
138 }
139
140 static void
141 panel_redraw_handler(struct window *window, void *data)
142 {
143         cairo_surface_t *surface;
144         cairo_t *cr;
145
146         window_draw(window);
147         surface = window_get_surface(window);
148         cr = cairo_create(surface);
149         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
150         cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.9);
151         cairo_paint(cr);
152
153         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
154         cairo_translate(cr, 10, 32 / 2);
155         window_for_each_item(window, panel_draw_item, cr);
156
157         cairo_destroy(cr);
158         cairo_surface_destroy(surface);
159         window_flush(window);
160 }
161
162 static void
163 panel_item_focus_handler(struct window *window,
164                          struct item *focus, void *data)
165 {
166         window_schedule_redraw(window);
167 }
168
169 static void
170 panel_button_handler(struct window *window,
171                      struct input *input, uint32_t time,
172                      int button, int state, void *data)
173 {
174         struct panel *panel = data;
175         struct panel_item *pi;
176         struct item *focus;
177
178         focus = window_get_focus_item(panel->window);
179         if (focus && button == BTN_LEFT) {
180                 pi = item_get_user_data(focus);
181                 window_schedule_redraw(panel->window);
182                 if (state == 0)
183                         panel_activate_item(panel, pi);
184         } else if (button == BTN_RIGHT) {
185                 if (state)
186                         show_menu(panel, input);
187                 else
188                         window_destroy(panel->menu);
189         }
190 }
191
192 static struct panel *
193 panel_create(struct display *display)
194 {
195         struct panel *panel;
196
197         panel = malloc(sizeof *panel);
198         memset(panel, 0, sizeof *panel);
199
200         panel->window = window_create(display, 0, 0);
201
202         window_set_title(panel->window, "panel");
203         window_set_decoration(panel->window, 0);
204         window_set_redraw_handler(panel->window, panel_redraw_handler);
205         window_set_custom(panel->window);
206         window_set_user_data(panel->window, panel);
207         window_set_button_handler(panel->window, panel_button_handler);
208         window_set_item_focus_handler(panel->window, panel_item_focus_handler);
209
210         return panel;
211 }
212
213 static void
214 panel_add_item(struct panel *panel, const char *icon, const char *path)
215 {
216         struct panel_item *item;
217
218         item = malloc(sizeof *item);
219         memset(item, 0, sizeof *item);
220         item->icon = cairo_image_surface_create_from_png(icon);
221         item->path = strdup(path);
222         item->panel = panel;
223         window_add_item(panel->window, item);
224 }
225
226 static void
227 background_draw(struct window *window, int width, int height, const char *path)
228 {
229         cairo_surface_t *surface, *image;
230         cairo_pattern_t *pattern;
231         cairo_matrix_t matrix;
232         cairo_t *cr;
233         double sx, sy;
234
235         window_set_child_size(window, width, height);
236         window_draw(window);
237         surface = window_get_surface(window);
238
239         cr = cairo_create(surface);
240         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
241         cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
242         cairo_paint(cr);
243
244         if (path) {
245                 image = load_jpeg(path);
246                 pattern = cairo_pattern_create_for_surface(image);
247                 sx = (double) cairo_image_surface_get_width(image) / width;
248                 sy = (double) cairo_image_surface_get_height(image) / height;
249                 cairo_matrix_init_scale(&matrix, sx, sy);
250                 cairo_pattern_set_matrix(pattern, &matrix);
251                 cairo_set_source(cr, pattern);
252                 cairo_pattern_destroy (pattern);
253                 cairo_paint(cr);
254                 cairo_surface_destroy(image);
255         }
256
257         cairo_destroy(cr);
258         cairo_surface_destroy(surface);
259         window_flush(window);
260 }
261
262 static void
263 desktop_shell_configure(void *data,
264                         struct desktop_shell *desktop_shell,
265                         uint32_t time, uint32_t edges,
266                         struct wl_surface *surface,
267                         int32_t width, int32_t height)
268 {
269         struct desktop *desktop = data;
270
271         if (surface == window_get_wl_surface(desktop->panel->window)) {
272                 window_set_child_size(desktop->panel->window, width, 32);
273                 window_schedule_redraw(desktop->panel->window);
274         } else if (surface == window_get_wl_surface(desktop->background)) {
275                 background_draw(desktop->background,
276                                 width, height, desktop->background_path);
277         }
278 }
279
280 static const struct desktop_shell_listener listener = {
281         desktop_shell_configure
282 };
283
284 static void
285 global_handler(struct wl_display *display, uint32_t id,
286                const char *interface, uint32_t version, void *data)
287 {
288         struct desktop *desktop = data;
289
290         if (!strcmp(interface, "desktop_shell")) {
291                 desktop->shell =
292                         wl_display_bind(display, id, &desktop_shell_interface);
293                 desktop_shell_add_listener(desktop->shell, &listener, desktop);
294         }
295 }
296
297 static const struct {
298         const char *icon;
299         const char *path;
300 } launchers[] = {
301         {
302                 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
303                 "/usr/bin/gnome-terminal"
304         },
305         {
306                 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
307                 "./clients/terminal"
308         },
309         {
310                 "/usr/share/icons/hicolor/24x24/apps/google-chrome.png",
311                 "/usr/bin/google-chrome"
312         },
313 };
314
315 int main(int argc, char *argv[])
316 {
317         struct desktop desktop;
318         int i;
319
320         desktop.display = display_create(&argc, &argv, NULL);
321         if (desktop.display == NULL) {
322                 fprintf(stderr, "failed to create display: %m\n");
323                 return -1;
324         }
325
326         wl_display_add_global_listener(display_get_display(desktop.display),
327                                        global_handler, &desktop);
328
329         desktop.panel = panel_create(desktop.display);
330
331         for (i = 0; i < ARRAY_LENGTH(launchers); i++)
332                 panel_add_item(desktop.panel,
333                                launchers[i].icon, launchers[i].path);
334
335         desktop_shell_set_panel(desktop.shell,
336                                 window_get_wl_surface(desktop.panel->window));
337
338         desktop.background = window_create(desktop.display, 0, 0);
339         window_set_decoration(desktop.background, 0);
340         window_set_custom(desktop.background);
341         desktop.background_path = argv[1];
342         desktop_shell_set_background(desktop.shell,
343                                      window_get_wl_surface(desktop.background));
344
345         signal(SIGCHLD, sigchild_handler);
346
347         display_run(desktop.display);
348
349         return 0;
350 }