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 <sys/timerfd.h>
34 #include <sys/epoll.h>
35 #include <linux/input.h>
39 #include <wayland-client.h>
41 #include "../shared/cairo-util.h"
42 #include "../shared/config-parser.h"
44 #include "desktop-shell-client-protocol.h"
47 struct display *display;
48 struct desktop_shell *shell;
49 struct unlock_dialog *unlock_dialog;
50 struct task unlock_task;
51 struct wl_list outputs;
53 struct window *busy_window;
54 struct widget *busy_widget;
58 void (*configure)(void *data,
59 struct desktop_shell *desktop_shell,
60 uint32_t edges, struct window *window,
61 int32_t width, int32_t height);
66 struct window *window;
67 struct widget *widget;
68 struct wl_list launcher_list;
69 struct panel_clock *clock;
74 struct window *window;
75 struct widget *widget;
79 struct wl_output *output;
83 struct background *background;
86 struct panel_launcher {
87 struct widget *widget;
89 cairo_surface_t *icon;
96 struct widget *widget;
98 struct task clock_task;
102 struct unlock_dialog {
103 struct window *window;
104 struct widget *widget;
105 struct widget *button;
108 struct desktop *desktop;
111 static char *key_background_image = DATADIR "/weston/pattern.png";
112 static char *key_background_type = "tile";
113 static uint32_t key_panel_color = 0xaa000000;
114 static uint32_t key_background_color = 0xff002244;
115 static char *key_launcher_icon;
116 static char *key_launcher_path;
117 static void launcher_section_done(void *data);
118 static int key_locking = 1;
120 static const struct config_key shell_config_keys[] = {
121 { "background-image", CONFIG_KEY_STRING, &key_background_image },
122 { "background-type", CONFIG_KEY_STRING, &key_background_type },
123 { "panel-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_panel_color },
124 { "background-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_background_color },
125 { "locking", CONFIG_KEY_BOOLEAN, &key_locking },
128 static const struct config_key launcher_config_keys[] = {
129 { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
130 { "path", CONFIG_KEY_STRING, &key_launcher_path },
133 static const struct config_section config_sections[] = {
135 shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
137 launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
138 launcher_section_done }
142 sigchild_handler(int s)
147 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
148 fprintf(stderr, "child %d exited\n", pid);
152 menu_func(struct window *window, int index, void *data)
154 printf("Selected index %d from a panel menu.\n", index);
158 show_menu(struct panel *panel, struct input *input, uint32_t time)
161 static const char *entries[] = {
162 "Roy", "Pris", "Leon", "Zhora"
165 input_get_position(input, &x, &y);
166 window_show_menu(window_get_display(panel->window),
167 input, time, panel->window,
168 x - 10, y - 10, menu_func, entries, 4);
172 panel_launcher_activate(struct panel_launcher *widget)
178 fprintf(stderr, "fork failed: %m\n");
185 if (execl(widget->path, widget->path, NULL) < 0) {
186 fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
192 panel_launcher_redraw_handler(struct widget *widget, void *data)
194 struct panel_launcher *launcher = data;
195 cairo_surface_t *surface;
196 struct rectangle allocation;
199 surface = window_get_surface(launcher->panel->window);
200 cr = cairo_create(surface);
202 widget_get_allocation(widget, &allocation);
203 if (launcher->pressed) {
208 cairo_set_source_surface(cr, launcher->icon,
209 allocation.x, allocation.y);
212 if (launcher->focused) {
213 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
214 cairo_mask_surface(cr, launcher->icon,
215 allocation.x, allocation.y);
222 panel_launcher_motion_handler(struct widget *widget, struct input *input,
223 uint32_t time, float x, float y, void *data)
225 struct panel_launcher *launcher = data;
227 widget_set_tooltip(widget, basename((char *)launcher->path), x, y);
229 return CURSOR_LEFT_PTR;
233 set_hex_color(cairo_t *cr, uint32_t color)
235 cairo_set_source_rgba(cr,
236 ((color >> 16) & 0xff) / 255.0,
237 ((color >> 8) & 0xff) / 255.0,
238 ((color >> 0) & 0xff) / 255.0,
239 ((color >> 24) & 0xff) / 255.0);
243 panel_redraw_handler(struct widget *widget, void *data)
245 cairo_surface_t *surface;
247 struct panel *panel = data;
249 surface = window_get_surface(panel->window);
250 cr = cairo_create(surface);
251 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
252 set_hex_color(cr, key_panel_color);
256 cairo_surface_destroy(surface);
260 panel_launcher_enter_handler(struct widget *widget, struct input *input,
261 float x, float y, void *data)
263 struct panel_launcher *launcher = data;
265 launcher->focused = 1;
266 widget_schedule_redraw(widget);
268 return CURSOR_LEFT_PTR;
272 panel_launcher_leave_handler(struct widget *widget,
273 struct input *input, void *data)
275 struct panel_launcher *launcher = data;
277 launcher->focused = 0;
278 widget_destroy_tooltip(widget);
279 widget_schedule_redraw(widget);
283 panel_launcher_button_handler(struct widget *widget,
284 struct input *input, uint32_t time,
286 enum wl_pointer_button_state state, void *data)
288 struct panel_launcher *launcher;
290 launcher = widget_get_user_data(widget);
291 widget_schedule_redraw(widget);
292 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
293 panel_launcher_activate(launcher);
297 clock_func(struct task *task, uint32_t events)
299 struct panel_clock *clock =
300 container_of(task, struct panel_clock, clock_task);
303 read(clock->clock_fd, &exp, sizeof exp);
304 widget_schedule_redraw(clock->widget);
308 panel_clock_redraw_handler(struct widget *widget, void *data)
310 cairo_surface_t *surface;
311 struct panel_clock *clock = data;
313 struct rectangle allocation;
314 cairo_text_extents_t extents;
315 cairo_font_extents_t font_extents;
317 struct tm * timeinfo;
321 timeinfo = localtime(&rawtime);
322 strftime(string, sizeof string, "%a %b %d, %I:%M %p", timeinfo);
324 widget_get_allocation(widget, &allocation);
325 if (allocation.width == 0)
328 surface = window_get_surface(clock->panel->window);
329 cr = cairo_create(surface);
330 cairo_select_font_face(cr, "sans",
331 CAIRO_FONT_SLANT_NORMAL,
332 CAIRO_FONT_WEIGHT_NORMAL);
333 cairo_set_font_size(cr, 14);
334 cairo_text_extents(cr, string, &extents);
335 cairo_font_extents (cr, &font_extents);
336 cairo_move_to(cr, allocation.x + 5,
337 allocation.y + 3 * (allocation.height >> 2) + 1);
338 cairo_set_source_rgb(cr, 0, 0, 0);
339 cairo_show_text(cr, string);
340 cairo_move_to(cr, allocation.x + 4,
341 allocation.y + 3 * (allocation.height >> 2));
342 cairo_set_source_rgb(cr, 1, 1, 1);
343 cairo_show_text(cr, string);
348 clock_timer_reset(struct panel_clock *clock)
350 struct itimerspec its;
352 its.it_interval.tv_sec = 60;
353 its.it_interval.tv_nsec = 0;
354 its.it_value.tv_sec = 60;
355 its.it_value.tv_nsec = 0;
356 if (timerfd_settime(clock->clock_fd, 0, &its, NULL) < 0) {
357 fprintf(stderr, "could not set timerfd\n: %m");
365 panel_add_clock(struct panel *panel)
367 struct panel_clock *clock;
370 timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
372 fprintf(stderr, "could not create timerfd\n: %m");
376 clock = malloc(sizeof *clock);
377 memset(clock, 0, sizeof *clock);
378 clock->panel = panel;
379 panel->clock = clock;
380 clock->clock_fd = timerfd;
382 clock->clock_task.run = clock_func;
383 display_watch_fd(window_get_display(panel->window), clock->clock_fd,
384 EPOLLIN, &clock->clock_task);
385 clock_timer_reset(clock);
387 clock->widget = widget_add_widget(panel->widget, clock);
388 widget_set_redraw_handler(clock->widget, panel_clock_redraw_handler);
392 panel_button_handler(struct widget *widget,
393 struct input *input, uint32_t time,
395 enum wl_pointer_button_state state, void *data)
397 struct panel *panel = data;
399 if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED)
400 show_menu(panel, input, time);
404 panel_resize_handler(struct widget *widget,
405 int32_t width, int32_t height, void *data)
407 struct panel_launcher *launcher;
408 struct panel *panel = data;
413 wl_list_for_each(launcher, &panel->launcher_list, link) {
414 w = cairo_image_surface_get_width(launcher->icon);
415 h = cairo_image_surface_get_height(launcher->icon);
416 widget_set_allocation(launcher->widget,
417 x, y - h / 2, w + 1, h + 1);
424 widget_set_allocation(panel->clock->widget,
425 width - w - 8, y - h / 2, w + 1, h + 1);
429 panel_configure(void *data,
430 struct desktop_shell *desktop_shell,
431 uint32_t edges, struct window *window,
432 int32_t width, int32_t height)
434 struct surface *surface = window_get_user_data(window);
435 struct panel *panel = container_of(surface, struct panel, base);
437 window_schedule_resize(panel->window, width, 32);
440 static struct panel *
441 panel_create(struct display *display)
445 panel = malloc(sizeof *panel);
446 memset(panel, 0, sizeof *panel);
448 panel->base.configure = panel_configure;
449 panel->window = window_create(display);
450 panel->widget = window_add_widget(panel->window, panel);
451 wl_list_init(&panel->launcher_list);
453 window_set_title(panel->window, "panel");
454 window_set_custom(panel->window);
455 window_set_user_data(panel->window, panel);
457 widget_set_redraw_handler(panel->widget, panel_redraw_handler);
458 widget_set_resize_handler(panel->widget, panel_resize_handler);
459 widget_set_button_handler(panel->widget, panel_button_handler);
461 panel_add_clock(panel);
467 panel_add_launcher(struct panel *panel, const char *icon, const char *path)
469 struct panel_launcher *launcher;
471 launcher = malloc(sizeof *launcher);
472 memset(launcher, 0, sizeof *launcher);
473 launcher->icon = cairo_image_surface_create_from_png(icon);
474 launcher->path = strdup(path);
475 launcher->panel = panel;
476 wl_list_insert(panel->launcher_list.prev, &launcher->link);
478 launcher->widget = widget_add_widget(panel->widget, launcher);
479 widget_set_enter_handler(launcher->widget,
480 panel_launcher_enter_handler);
481 widget_set_leave_handler(launcher->widget,
482 panel_launcher_leave_handler);
483 widget_set_button_handler(launcher->widget,
484 panel_launcher_button_handler);
485 widget_set_redraw_handler(launcher->widget,
486 panel_launcher_redraw_handler);
487 widget_set_motion_handler(launcher->widget,
488 panel_launcher_motion_handler);
497 background_draw(struct widget *widget, void *data)
499 struct background *background = data;
500 cairo_surface_t *surface, *image;
501 cairo_pattern_t *pattern;
502 cairo_matrix_t matrix;
505 struct rectangle allocation;
508 surface = window_get_surface(background->window);
510 cr = cairo_create(surface);
511 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
512 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
515 widget_get_allocation(widget, &allocation);
517 if (key_background_image)
518 image = load_cairo_surface(key_background_image);
520 if (strcmp(key_background_type, "scale") == 0)
521 type = BACKGROUND_SCALE;
522 else if (strcmp(key_background_type, "tile") == 0)
523 type = BACKGROUND_TILE;
525 fprintf(stderr, "invalid background-type: %s\n",
526 key_background_type);
528 if (image && type != -1) {
529 pattern = cairo_pattern_create_for_surface(image);
531 case BACKGROUND_SCALE:
532 sx = (double) cairo_image_surface_get_width(image) /
534 sy = (double) cairo_image_surface_get_height(image) /
536 cairo_matrix_init_scale(&matrix, sx, sy);
537 cairo_pattern_set_matrix(pattern, &matrix);
539 case BACKGROUND_TILE:
540 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
543 cairo_set_source(cr, pattern);
544 cairo_pattern_destroy (pattern);
545 cairo_surface_destroy(image);
547 set_hex_color(cr, key_background_color);
552 cairo_surface_destroy(surface);
556 background_configure(void *data,
557 struct desktop_shell *desktop_shell,
558 uint32_t edges, struct window *window,
559 int32_t width, int32_t height)
561 struct background *background =
562 (struct background *) window_get_user_data(window);
564 widget_schedule_resize(background->widget, width, height);
568 unlock_dialog_redraw_handler(struct widget *widget, void *data)
570 struct unlock_dialog *dialog = data;
571 struct rectangle allocation;
573 cairo_surface_t *surface;
574 cairo_pattern_t *pat;
577 surface = window_get_surface(dialog->window);
578 cr = cairo_create(surface);
580 widget_get_allocation(dialog->widget, &allocation);
581 cairo_rectangle(cr, allocation.x, allocation.y,
582 allocation.width, allocation.height);
583 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
584 cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
587 cairo_translate(cr, allocation.x, allocation.y);
588 if (dialog->button_focused)
593 cx = allocation.width / 2.0;
594 cy = allocation.height / 2.0;
595 r = (cx < cy ? cx : cy) * 0.4;
596 pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
597 cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
598 cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
599 cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
600 cairo_set_source(cr, pat);
601 cairo_pattern_destroy(pat);
602 cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
605 widget_set_allocation(dialog->button,
606 allocation.x + cx - r,
607 allocation.y + cy - r, 2 * r, 2 * r);
611 cairo_surface_destroy(surface);
615 unlock_dialog_button_handler(struct widget *widget,
616 struct input *input, uint32_t time,
618 enum wl_pointer_button_state state, void *data)
620 struct unlock_dialog *dialog = data;
621 struct desktop *desktop = dialog->desktop;
623 if (button == BTN_LEFT) {
624 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
626 display_defer(desktop->display, &desktop->unlock_task);
633 unlock_dialog_keyboard_focus_handler(struct window *window,
634 struct input *device, void *data)
636 window_schedule_redraw(window);
640 unlock_dialog_widget_enter_handler(struct widget *widget,
642 float x, float y, void *data)
644 struct unlock_dialog *dialog = data;
646 dialog->button_focused = 1;
647 widget_schedule_redraw(widget);
649 return CURSOR_LEFT_PTR;
653 unlock_dialog_widget_leave_handler(struct widget *widget,
654 struct input *input, void *data)
656 struct unlock_dialog *dialog = data;
658 dialog->button_focused = 0;
659 widget_schedule_redraw(widget);
662 static struct unlock_dialog *
663 unlock_dialog_create(struct desktop *desktop)
665 struct display *display = desktop->display;
666 struct unlock_dialog *dialog;
668 dialog = malloc(sizeof *dialog);
671 memset(dialog, 0, sizeof *dialog);
673 dialog->window = window_create(display);
674 dialog->widget = frame_create(dialog->window, dialog);
675 window_set_title(dialog->window, "Unlock your desktop");
676 window_set_custom(dialog->window);
678 window_set_user_data(dialog->window, dialog);
679 window_set_keyboard_focus_handler(dialog->window,
680 unlock_dialog_keyboard_focus_handler);
681 dialog->button = widget_add_widget(dialog->widget, dialog);
682 widget_set_redraw_handler(dialog->widget,
683 unlock_dialog_redraw_handler);
684 widget_set_enter_handler(dialog->button,
685 unlock_dialog_widget_enter_handler);
686 widget_set_leave_handler(dialog->button,
687 unlock_dialog_widget_leave_handler);
688 widget_set_button_handler(dialog->button,
689 unlock_dialog_button_handler);
691 desktop_shell_set_lock_surface(desktop->shell,
692 window_get_wl_shell_surface(dialog->window));
694 window_schedule_resize(dialog->window, 260, 230);
700 unlock_dialog_destroy(struct unlock_dialog *dialog)
702 window_destroy(dialog->window);
707 unlock_dialog_finish(struct task *task, uint32_t events)
709 struct desktop *desktop =
710 container_of(task, struct desktop, unlock_task);
712 desktop_shell_unlock(desktop->shell);
713 unlock_dialog_destroy(desktop->unlock_dialog);
714 desktop->unlock_dialog = NULL;
718 desktop_shell_configure(void *data,
719 struct desktop_shell *desktop_shell,
721 struct wl_shell_surface *shell_surface,
722 int32_t width, int32_t height)
724 struct window *window = wl_shell_surface_get_user_data(shell_surface);
725 struct surface *s = window_get_user_data(window);
727 s->configure(data, desktop_shell, edges, window, width, height);
731 desktop_shell_prepare_lock_surface(void *data,
732 struct desktop_shell *desktop_shell)
734 struct desktop *desktop = data;
737 desktop_shell_unlock(desktop->shell);
741 if (!desktop->unlock_dialog) {
742 desktop->unlock_dialog = unlock_dialog_create(desktop);
743 desktop->unlock_dialog->desktop = desktop;
747 static const struct desktop_shell_listener listener = {
748 desktop_shell_configure,
749 desktop_shell_prepare_lock_surface
752 static struct background *
753 background_create(struct desktop *desktop)
755 struct background *background;
757 background = malloc(sizeof *background);
758 memset(background, 0, sizeof *background);
760 background->base.configure = background_configure;
761 background->window = window_create(desktop->display);
762 background->widget = window_add_widget(background->window, background);
763 window_set_custom(background->window);
764 window_set_user_data(background->window, background);
765 widget_set_redraw_handler(background->widget, background_draw);
771 busy_surface_enter_handler(struct widget *widget, struct input *input,
772 float x, float y, void *data)
778 busy_surface_create(struct desktop *desktop)
780 struct wl_surface *s;
782 desktop->busy_window = window_create(desktop->display);
783 s = window_get_wl_surface(desktop->busy_window);
784 desktop_shell_set_busy_surface(desktop->shell, s);
786 desktop->busy_widget =
787 window_add_widget(desktop->busy_window, desktop);
788 /* We set the allocation to 1x1 at 0,0 so the fake enter event
789 * at 0,0 will go to this widget. */
790 widget_set_allocation(desktop->busy_widget, 0, 0, 1, 1);
792 widget_set_enter_handler(desktop->busy_widget,
793 busy_surface_enter_handler);
797 create_output(struct desktop *desktop, uint32_t id)
799 struct output *output;
801 output = calloc(1, sizeof *output);
805 output->output = wl_display_bind(display_get_display(desktop->display),
806 id, &wl_output_interface);
808 wl_list_insert(&desktop->outputs, &output->link);
812 global_handler(struct wl_display *display, uint32_t id,
813 const char *interface, uint32_t version, void *data)
815 struct desktop *desktop = data;
817 if (!strcmp(interface, "desktop_shell")) {
819 wl_display_bind(display, id, &desktop_shell_interface);
820 desktop_shell_add_listener(desktop->shell, &listener, desktop);
821 } else if (!strcmp(interface, "wl_output")) {
822 create_output(desktop, id);
827 launcher_section_done(void *data)
829 struct desktop *desktop = data;
830 struct output *output;
832 if (key_launcher_icon == NULL || key_launcher_path == NULL) {
833 fprintf(stderr, "invalid launcher section\n");
837 wl_list_for_each(output, &desktop->outputs, link) {
838 panel_add_launcher(output->panel,
839 key_launcher_icon, key_launcher_path);
842 free(key_launcher_icon);
843 key_launcher_icon = NULL;
844 free(key_launcher_path);
845 key_launcher_path = NULL;
849 add_default_launcher(struct desktop *desktop)
851 struct output *output;
853 wl_list_for_each(output, &desktop->outputs, link)
854 panel_add_launcher(output->panel,
855 DATADIR "/weston/terminal.png",
856 BINDIR "/weston-terminal");
859 int main(int argc, char *argv[])
861 struct desktop desktop = { 0 };
863 struct output *output;
866 desktop.unlock_task.run = unlock_dialog_finish;
867 wl_list_init(&desktop.outputs);
869 desktop.display = display_create(argc, argv);
870 if (desktop.display == NULL) {
871 fprintf(stderr, "failed to create display: %m\n");
875 display_set_user_data(desktop.display, &desktop);
876 wl_display_add_global_listener(display_get_display(desktop.display),
877 global_handler, &desktop);
879 wl_list_for_each(output, &desktop.outputs, link) {
880 struct wl_shell_surface *s;
882 output->panel = panel_create(desktop.display);
883 s = window_get_wl_shell_surface(output->panel->window);
884 desktop_shell_set_panel(desktop.shell, output->output, s);
886 output->background = background_create(&desktop);
887 s = window_get_wl_shell_surface(output->background->window);
888 desktop_shell_set_background(desktop.shell, output->output, s);
891 busy_surface_create(&desktop);
893 config_file = config_file_path("weston.ini");
894 ret = parse_config_file(config_file,
895 config_sections, ARRAY_LENGTH(config_sections),
899 add_default_launcher(&desktop);
901 signal(SIGCHLD, sigchild_handler);
903 display_run(desktop.display);