diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index b437ed8c..2ba4fcd0 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -1,5 +1,6 @@ /* * Copyright © 2011 Kristian Høgsberg + * Copyright © 2011 Collabora, Ltd. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -43,6 +44,8 @@ struct desktop { struct panel *panel; struct window *background; const char *background_path; + struct unlock_dialog *unlock_dialog; + struct task unlock_task; }; struct panel { @@ -58,6 +61,14 @@ struct panel_item { const char *path; }; +struct unlock_dialog { + struct window *window; + struct item *button; + int closing; + + struct desktop *desktop; +}; + static char *key_background_image; static uint32_t key_panel_color; static char *key_launcher_icon; @@ -293,6 +304,144 @@ background_draw(struct window *window, int width, int height, const char *path) window_flush(window); } +static void +unlock_dialog_draw(struct unlock_dialog *dialog) +{ + struct rectangle allocation; + cairo_t *cr; + cairo_surface_t *surface; + cairo_pattern_t *pat; + double cx, cy, r, f; + + window_draw(dialog->window); + + surface = window_get_surface(dialog->window); + cr = cairo_create(surface); + window_get_child_allocation(dialog->window, &allocation); + cairo_rectangle(cr, allocation.x, allocation.y, + allocation.width, allocation.height); + cairo_clip(cr); + cairo_push_group(cr); + cairo_translate(cr, allocation.x, allocation.y); + + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0, 0, 0, 0.6); + cairo_paint(cr); + + if (window_get_focus_item(dialog->window) == dialog->button) + f = 1.0; + else + f = 0.7; + + cx = allocation.width / 2.0; + cy = allocation.height / 2.0; + r = (cx < cy ? cx : cy) * 0.4; + pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r); + cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0); + cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f); + cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0); + cairo_set_source(cr, pat); + cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI); + cairo_fill(cr); + + item_set_allocation(dialog->button, + allocation.x + cx - r, + allocation.y + cy - r, 2 * r, 2 * r); + cairo_pattern_destroy(pat); + + cairo_pop_group_to_source(cr); + cairo_paint(cr); + cairo_destroy(cr); + + window_flush(dialog->window); + cairo_surface_destroy(surface); +} + +static void +unlock_dialog_button_handler(struct window *window, + struct input *input, uint32_t time, + int button, int state, void *data) +{ + struct unlock_dialog *dialog = data; + struct desktop *desktop = dialog->desktop; + struct item *focus; + + focus = window_get_focus_item(dialog->window); + if (focus && button == BTN_LEFT) { + if (state == 0 && !dialog->closing) { + display_defer(desktop->display, &desktop->unlock_task); + dialog->closing = 1; + } + } +} + +static void +unlock_dialog_redraw_handler(struct window *window, void *data) +{ + struct unlock_dialog *dialog = data; + + unlock_dialog_draw(dialog); +} + +static void +unlock_dialog_keyboard_focus_handler(struct window *window, + struct input *device, void *data) +{ + window_schedule_redraw(window); +} + +static void +unlock_dialog_item_focus_handler(struct window *window, + struct item *focus, void *data) +{ + window_schedule_redraw(window); +} + +static struct unlock_dialog * +unlock_dialog_create(struct display *display) +{ + struct unlock_dialog *dialog; + + dialog = malloc(sizeof *dialog); + if (!dialog) + return NULL; + memset(dialog, 0, sizeof *dialog); + + dialog->window = window_create(display, 260, 230); + window_set_title(dialog->window, "Unlock your desktop"); + + window_set_user_data(dialog->window, dialog); + window_set_redraw_handler(dialog->window, unlock_dialog_redraw_handler); + window_set_keyboard_focus_handler(dialog->window, + unlock_dialog_keyboard_focus_handler); + window_set_button_handler(dialog->window, unlock_dialog_button_handler); + window_set_item_focus_handler(dialog->window, + unlock_dialog_item_focus_handler); + dialog->button = window_add_item(dialog->window, NULL); + + unlock_dialog_draw(dialog); + + return dialog; +} + +static void +unlock_dialog_destroy(struct unlock_dialog *dialog) +{ + window_destroy(dialog->window); + free(dialog); +} + +static void +unlock_dialog_finish(struct task *task, uint32_t events) +{ + struct desktop *desktop = + container_of(task, struct desktop, unlock_task); + + desktop_shell_unlock(desktop->shell); + unlock_dialog_destroy(desktop->unlock_dialog); + desktop->unlock_dialog = NULL; +} + static void desktop_shell_configure(void *data, struct desktop_shell *desktop_shell, @@ -315,8 +464,16 @@ static void desktop_shell_prepare_lock_surface(void *data, struct desktop_shell *desktop_shell) { - /* no-op for now */ - desktop_shell_unlock(desktop_shell); + struct desktop *desktop = data; + + if (!desktop->unlock_dialog) { + desktop->unlock_dialog = + unlock_dialog_create(desktop->display); + desktop->unlock_dialog->desktop = desktop; + } + + desktop_shell_set_lock_surface(desktop_shell, + window_get_wl_surface(desktop->unlock_dialog->window)); } static const struct desktop_shell_listener listener = { @@ -356,9 +513,11 @@ launcher_section_done(void *data) int main(int argc, char *argv[]) { - struct desktop desktop; + struct desktop desktop = { 0 }; char *config_file; + desktop.unlock_task.run = unlock_dialog_finish; + desktop.display = display_create(&argc, &argv, NULL); if (desktop.display == NULL) { fprintf(stderr, "failed to create display: %m\n");