2 * Copyright © 2011 Kristian Høgsberg
3 * Copyright © 2011 Collabora, Ltd.
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.
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
33 #include <linux/input.h>
35 #include "wayland-client.h"
36 #include "cairo-util.h"
39 #include <desktop-shell-client-protocol.h>
42 struct display *display;
43 struct desktop_shell *shell;
45 struct window *background;
46 const char *background_path;
47 struct unlock_dialog *unlock_dialog;
48 struct task unlock_task;
52 struct window *window;
59 cairo_surface_t *icon;
64 struct unlock_dialog {
65 struct window *window;
69 struct desktop *desktop;
72 static char *key_background_image;
73 static uint32_t key_panel_color;
74 static char *key_launcher_icon;
75 static char *key_launcher_path;
76 static void launcher_section_done(void *data);
78 static const struct config_key shell_config_keys[] = {
79 { "background-image", CONFIG_KEY_STRING, &key_background_image },
80 { "panel-color", CONFIG_KEY_INTEGER, &key_panel_color },
83 static const struct config_key launcher_config_keys[] = {
84 { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
85 { "path", CONFIG_KEY_STRING, &key_launcher_path },
88 static const struct config_section config_sections[] = {
89 { "wayland-desktop-shell",
90 shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
92 launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
93 launcher_section_done }
97 sigchild_handler(int s)
102 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
103 fprintf(stderr, "child %d exited\n", pid);
107 show_menu(struct panel *panel, struct input *input)
109 int32_t x, y, width = 200, height = 200;
110 struct display *display;
112 input_get_position(input, &x, &y);
113 display = window_get_display(panel->window);
114 panel->menu = window_create_transient(display, panel->window,
115 x - 10, y - 10, width, height);
117 window_draw(panel->menu);
118 window_flush(panel->menu);
122 panel_activate_item(struct panel *panel, struct panel_item *item)
128 fprintf(stderr, "fork failed: %m\n");
135 if (execl(item->path, item->path, NULL) < 0) {
136 fprintf(stderr, "execl failed: %m\n");
142 panel_draw_item(struct item *item, void *data)
145 struct panel_item *pi;
146 int x, y, width, height;
149 pi = item_get_user_data(item);
150 width = cairo_image_surface_get_width(pi->icon);
151 height = cairo_image_surface_get_height(pi->icon);
161 cairo_user_to_device(cr, &dx, &dy);
162 item_set_allocation(item, dx, dy, width, height);
164 cairo_set_source_surface(cr, pi->icon, x, y);
167 if (window_get_focus_item(pi->panel->window) == item) {
168 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
169 cairo_mask_surface(cr, pi->icon, x, y);
172 cairo_translate(cr, width + 10, 0);
176 set_hex_color(cairo_t *cr, uint32_t color)
178 cairo_set_source_rgba(cr,
179 ((color >> 16) & 0xff) / 255.0,
180 ((color >> 8) & 0xff) / 255.0,
181 ((color >> 0) & 0xff) / 255.0,
182 ((color >> 24) & 0xff) / 255.0);
186 panel_redraw_handler(struct window *window, void *data)
188 cairo_surface_t *surface;
192 surface = window_get_surface(window);
193 cr = cairo_create(surface);
194 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
195 set_hex_color(cr, key_panel_color);
198 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
199 cairo_translate(cr, 10, 32 / 2);
200 window_for_each_item(window, panel_draw_item, cr);
203 cairo_surface_destroy(surface);
204 window_flush(window);
208 panel_item_focus_handler(struct window *window,
209 struct item *focus, void *data)
211 window_schedule_redraw(window);
215 panel_button_handler(struct window *window,
216 struct input *input, uint32_t time,
217 int button, int state, void *data)
219 struct panel *panel = data;
220 struct panel_item *pi;
223 focus = window_get_focus_item(panel->window);
224 if (focus && button == BTN_LEFT) {
225 pi = item_get_user_data(focus);
226 window_schedule_redraw(panel->window);
228 panel_activate_item(panel, pi);
229 } else if (button == BTN_RIGHT) {
231 show_menu(panel, input);
233 window_destroy(panel->menu);
237 static struct panel *
238 panel_create(struct display *display)
242 panel = malloc(sizeof *panel);
243 memset(panel, 0, sizeof *panel);
245 panel->window = window_create(display, 0, 0);
247 window_set_title(panel->window, "panel");
248 window_set_decoration(panel->window, 0);
249 window_set_redraw_handler(panel->window, panel_redraw_handler);
250 window_set_custom(panel->window);
251 window_set_user_data(panel->window, panel);
252 window_set_button_handler(panel->window, panel_button_handler);
253 window_set_item_focus_handler(panel->window, panel_item_focus_handler);
259 panel_add_item(struct panel *panel, const char *icon, const char *path)
261 struct panel_item *item;
263 item = malloc(sizeof *item);
264 memset(item, 0, sizeof *item);
265 item->icon = cairo_image_surface_create_from_png(icon);
266 item->path = strdup(path);
268 window_add_item(panel->window, item);
272 background_draw(struct window *window, int width, int height, const char *path)
274 cairo_surface_t *surface, *image;
275 cairo_pattern_t *pattern;
276 cairo_matrix_t matrix;
280 window_set_child_size(window, width, height);
282 surface = window_get_surface(window);
284 cr = cairo_create(surface);
285 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
286 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
290 image = load_jpeg(path);
291 pattern = cairo_pattern_create_for_surface(image);
292 sx = (double) cairo_image_surface_get_width(image) / width;
293 sy = (double) cairo_image_surface_get_height(image) / height;
294 cairo_matrix_init_scale(&matrix, sx, sy);
295 cairo_pattern_set_matrix(pattern, &matrix);
296 cairo_set_source(cr, pattern);
297 cairo_pattern_destroy (pattern);
299 cairo_surface_destroy(image);
303 cairo_surface_destroy(surface);
304 window_flush(window);
308 unlock_dialog_draw(struct unlock_dialog *dialog)
310 struct rectangle allocation;
312 cairo_surface_t *surface;
313 cairo_pattern_t *pat;
316 window_draw(dialog->window);
318 surface = window_get_surface(dialog->window);
319 cr = cairo_create(surface);
320 window_get_child_allocation(dialog->window, &allocation);
321 cairo_rectangle(cr, allocation.x, allocation.y,
322 allocation.width, allocation.height);
324 cairo_push_group(cr);
325 cairo_translate(cr, allocation.x, allocation.y);
327 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
328 cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
331 if (window_get_focus_item(dialog->window) == dialog->button)
336 cx = allocation.width / 2.0;
337 cy = allocation.height / 2.0;
338 r = (cx < cy ? cx : cy) * 0.4;
339 pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
340 cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
341 cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
342 cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
343 cairo_set_source(cr, pat);
344 cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
347 item_set_allocation(dialog->button,
348 allocation.x + cx - r,
349 allocation.y + cy - r, 2 * r, 2 * r);
350 cairo_pattern_destroy(pat);
352 cairo_pop_group_to_source(cr);
356 window_flush(dialog->window);
357 cairo_surface_destroy(surface);
361 unlock_dialog_button_handler(struct window *window,
362 struct input *input, uint32_t time,
363 int button, int state, void *data)
365 struct unlock_dialog *dialog = data;
366 struct desktop *desktop = dialog->desktop;
369 focus = window_get_focus_item(dialog->window);
370 if (focus && button == BTN_LEFT) {
371 if (state == 0 && !dialog->closing) {
372 display_defer(desktop->display, &desktop->unlock_task);
379 unlock_dialog_redraw_handler(struct window *window, void *data)
381 struct unlock_dialog *dialog = data;
383 unlock_dialog_draw(dialog);
387 unlock_dialog_keyboard_focus_handler(struct window *window,
388 struct input *device, void *data)
390 window_schedule_redraw(window);
394 unlock_dialog_item_focus_handler(struct window *window,
395 struct item *focus, void *data)
397 window_schedule_redraw(window);
400 static struct unlock_dialog *
401 unlock_dialog_create(struct desktop *desktop)
403 struct display *display = desktop->display;
404 struct unlock_dialog *dialog;
406 dialog = malloc(sizeof *dialog);
409 memset(dialog, 0, sizeof *dialog);
411 dialog->window = window_create(display, 260, 230);
412 window_set_title(dialog->window, "Unlock your desktop");
414 window_set_user_data(dialog->window, dialog);
415 window_set_redraw_handler(dialog->window, unlock_dialog_redraw_handler);
416 window_set_keyboard_focus_handler(dialog->window,
417 unlock_dialog_keyboard_focus_handler);
418 window_set_button_handler(dialog->window, unlock_dialog_button_handler);
419 window_set_item_focus_handler(dialog->window,
420 unlock_dialog_item_focus_handler);
421 dialog->button = window_add_item(dialog->window, NULL);
423 desktop_shell_set_lock_surface(desktop->shell,
424 window_get_wl_surface(dialog->window));
426 unlock_dialog_draw(dialog);
432 unlock_dialog_destroy(struct unlock_dialog *dialog)
434 window_destroy(dialog->window);
439 unlock_dialog_finish(struct task *task, uint32_t events)
441 struct desktop *desktop =
442 container_of(task, struct desktop, unlock_task);
444 desktop_shell_unlock(desktop->shell);
445 unlock_dialog_destroy(desktop->unlock_dialog);
446 desktop->unlock_dialog = NULL;
450 desktop_shell_configure(void *data,
451 struct desktop_shell *desktop_shell,
452 uint32_t time, uint32_t edges,
453 struct wl_surface *surface,
454 int32_t width, int32_t height)
456 struct desktop *desktop = data;
458 if (surface == window_get_wl_surface(desktop->panel->window)) {
459 window_set_child_size(desktop->panel->window, width, 32);
460 window_schedule_redraw(desktop->panel->window);
461 } else if (surface == window_get_wl_surface(desktop->background)) {
462 background_draw(desktop->background,
463 width, height, desktop->background_path);
468 desktop_shell_prepare_lock_surface(void *data,
469 struct desktop_shell *desktop_shell)
471 struct desktop *desktop = data;
473 if (!desktop->unlock_dialog) {
474 desktop->unlock_dialog = unlock_dialog_create(desktop);
475 desktop->unlock_dialog->desktop = desktop;
479 static const struct desktop_shell_listener listener = {
480 desktop_shell_configure,
481 desktop_shell_prepare_lock_surface
485 global_handler(struct wl_display *display, uint32_t id,
486 const char *interface, uint32_t version, void *data)
488 struct desktop *desktop = data;
490 if (!strcmp(interface, "desktop_shell")) {
492 wl_display_bind(display, id, &desktop_shell_interface);
493 desktop_shell_add_listener(desktop->shell, &listener, desktop);
498 launcher_section_done(void *data)
500 struct desktop *desktop = data;
502 if (key_launcher_icon == NULL || key_launcher_path == NULL) {
503 fprintf(stderr, "invalid launcher section\n");
507 panel_add_item(desktop->panel, key_launcher_icon, key_launcher_path);
508 free(key_launcher_icon);
509 key_launcher_icon = NULL;
510 free(key_launcher_path);
511 key_launcher_path = NULL;
514 int main(int argc, char *argv[])
516 struct desktop desktop = { 0 };
519 desktop.unlock_task.run = unlock_dialog_finish;
521 desktop.display = display_create(&argc, &argv, NULL);
522 if (desktop.display == NULL) {
523 fprintf(stderr, "failed to create display: %m\n");
527 /* The fd is our private, do not confuse our children with it. */
528 unsetenv("WAYLAND_SOCKET");
530 wl_display_add_global_listener(display_get_display(desktop.display),
531 global_handler, &desktop);
533 desktop.panel = panel_create(desktop.display);
535 config_file = config_file_path("wayland-desktop-shell.ini");
536 parse_config_file(config_file,
537 config_sections, ARRAY_LENGTH(config_sections),
541 desktop_shell_set_panel(desktop.shell,
542 window_get_wl_surface(desktop.panel->window));
544 desktop.background = window_create(desktop.display, 0, 0);
545 window_set_decoration(desktop.background, 0);
546 window_set_custom(desktop.background);
547 desktop.background_path = key_background_image;
548 desktop_shell_set_background(desktop.shell,
549 window_get_wl_surface(desktop.background));
551 signal(SIGCHLD, sigchild_handler);
553 display_run(desktop.display);