Right-click dropdown menu for window list items. This patch introduces a simple minimize feature. The surface is removed from the layer list on minimize and re-added on unminimize. The close item sends the client a SIGTERM signal. --- clients/desktop-shell.c | 154 ++++++++++++++++++++++++++++++++-- src/shell.c | 214 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 357 insertions(+), 11 deletions(-)
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 2b5f7c8..582a19f 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -70,6 +70,7 @@ struct surface { struct desktop *desktop; uint32_t output_mask; char *title; + int minimized, focused; /* One window list item per panel of the surface's output_mask */ struct wl_list item_list; @@ -193,13 +194,13 @@ sigchild_handler(int s) } static void -menu_func(struct window *window, int index, void *data) +panel_menu_func(struct window *window, int index, void *data) { printf("Selected index %d from a panel menu.\n", index); } static void -show_menu(struct panel *panel, struct input *input, uint32_t time) +panel_show_menu(struct panel *panel, struct input *input, uint32_t time) { int32_t x, y; static const char *entries[] = { @@ -209,7 +210,7 @@ show_menu(struct panel *panel, struct input *input, uint32_t time) input_get_position(input, &x, &y); window_show_menu(window_get_display(panel->window), input, time, panel->window, - x - 10, y - 10, menu_func, entries, 4); + x - 10, y - 10, panel_menu_func, entries, 4); } static void @@ -463,7 +464,7 @@ panel_button_handler(struct widget *widget, struct panel *panel = data; if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED) - show_menu(panel, input, time); + panel_show_menu(panel, input, time); } static void @@ -1075,7 +1076,7 @@ panel_list_item_redraw_handler(struct widget *widget, void *data) surface = window_get_surface(item->panel->window); cr = cairo_create(surface); - if (item->focused) { + if (item->focused || item->surface->focused) { cairo_set_source_rgba(cr, item->panel->focused_item.r, item->panel->focused_item.g, item->panel->focused_item.b, @@ -1156,6 +1157,7 @@ panel_list_item_enter_handler(struct widget *widget, struct input *input, struct list_item *item = data; item->highlight = 1; + item->focused = 1; widget_schedule_redraw(widget); return CURSOR_LEFT_PTR; @@ -1168,18 +1170,116 @@ panel_list_item_leave_handler(struct widget *widget, struct list_item *item = data; item->highlight = 0; + item->focused = 0; widget_destroy_tooltip(widget); widget_schedule_redraw(widget); } static void +desktop_update_list_items(struct desktop *desktop, struct surface *surface); + +static void +list_item_menu_handle_button(struct list_item *item, int index) +{ + struct surface *surface = item->surface; + + switch (index) { + case 0: /* (Un)Minimize */ + if (surface->minimized) { + surface_data_unminimize(surface->surface_data); + surface->minimized = 0; + } + else { + surface_data_minimize(surface->surface_data); + surface->minimized = 1; + } + break; + case 1: /* Close */ + surface_data_close(surface->surface_data); + break; + default: + item->highlight = 0; + break; + } + + item->focused = 0; + + desktop_update_list_items(surface->desktop, surface); + widget_destroy_tooltip(item->widget); + widget_schedule_redraw(item->widget); +} + +static void +list_item_menu_func(struct window *window, int index, void *data) +{ + struct list_item *item; + struct panel *panel; + + panel = data; + + wl_list_for_each(item, &panel->window_list, link) + if (item->focused) { + list_item_menu_handle_button(item, index); + return; + } +} + +#define MENU_ENTRIES 2 + +static void +list_item_show_menu(struct list_item *item, struct input *input, uint32_t time) +{ + struct panel *panel; + int32_t x, y; + static const char *entries[MENU_ENTRIES]; + + entries[0] = item->surface->minimized ? "Unminimize" : "Minimize"; + entries[1] = "Close"; + + panel = item->panel; + input_get_position(input, &x, &y); + window_show_menu(window_get_display(panel->window), input, + time, panel->window, x - 10, y - 10, + list_item_menu_func, entries, MENU_ENTRIES); +} + +static void panel_list_item_button_handler(struct widget *widget, struct input *input, uint32_t time, uint32_t button, enum wl_pointer_button_state state, void *data) { + struct list_item *item; + struct surface *surface; + + item = data; + widget_schedule_redraw(widget); - /* TODO: Toggle minimize */ + + if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED) { + widget_destroy_tooltip(item->widget); + widget_schedule_redraw(item->widget); + list_item_show_menu(item, input, time); + return; + } + + if ((button != BTN_LEFT) || (state != WL_POINTER_BUTTON_STATE_RELEASED)) + return; + + surface = item->surface; + if (!surface->focused && !surface->minimized) { + surface_data_focus(surface->surface_data); + surface->focused = 1; + return; + } + if (surface->minimized) { + surface_data_unminimize(surface->surface_data); + surface->minimized = 0; + } + else { + surface_data_minimize(surface->surface_data); + surface->minimized = 1; + } } static struct list_item * @@ -1318,6 +1418,45 @@ surface_data_set_title(void *data, } static void +surface_data_set_minimized_state(void *data, + struct surface_data *surface_data, + int minimized) +{ + struct desktop *desktop; + struct surface *surface = data; + + desktop = surface->desktop; + + surface->minimized = minimized; + + desktop_update_list_items(desktop, surface); +} + +static void +surface_data_set_focused_state(void *data, + struct surface_data *surface_data, + int focused) +{ + struct desktop *desktop; + struct surface *surface = data, *es; + struct list_item *item; + + desktop = surface->desktop; + + wl_list_for_each(es, &desktop->surfaces, link) + if (es->surface_data != surface_data && focused) { + es->focused = 0; + wl_list_for_each(item, &es->item_list, surface_link) + if (!item->focused) + item->highlight = 0; + } + + surface->focused = focused; + + desktop_update_list_items(desktop, surface); +} + +static void surface_data_destroy_handler(void *data, struct surface_data *surface_data) { struct list_item *item, *next; @@ -1344,6 +1483,8 @@ surface_data_destroy_handler(void *data, struct surface_data *surface_data) static const struct surface_data_listener surface_data_listener = { surface_data_set_output_mask, surface_data_set_title, + surface_data_set_minimized_state, + surface_data_set_focused_state, surface_data_destroy_handler }; @@ -1362,6 +1503,7 @@ surface_data_receive_surface_object(void *data, exit(EXIT_FAILURE); } + surface->desktop = desktop; surface->surface_data = surface_data; surface->desktop = desktop; surface->title = strdup("unknown"); diff --git a/src/shell.c b/src/shell.c index 5f09a45..9e19ddb 100644 --- a/src/shell.c +++ b/src/shell.c @@ -67,6 +67,7 @@ struct workspace { struct weston_layer layer; struct wl_list focus_list; + struct wl_list minimized_list; struct wl_listener seat_destroyed_listener; }; @@ -178,11 +179,12 @@ struct shell_surface { struct weston_surface *parent; struct desktop_shell *shell; - enum shell_surface_type type, next_type; + enum shell_surface_type type, next_type, saved_type; char *title, *class; int32_t saved_x, saved_y; bool saved_position_valid; bool saved_rotation_valid; + int minimized; int unresponsive; struct { @@ -556,6 +558,7 @@ workspace_create(void) weston_layer_init(&ws->layer, NULL); wl_list_init(&ws->focus_list); + wl_list_init(&ws->minimized_list); wl_list_init(&ws->seat_destroyed_listener.link); ws->seat_destroyed_listener.notify = seat_destroyed; @@ -1419,16 +1422,163 @@ shell_surface_pong(struct wl_client *client, struct wl_resource *resource, } static void -surface_data_object_destroy(struct wl_resource *resource) +send_surface_data_focused_state(struct weston_surface *surface); + +static void +activate(struct desktop_shell *shell, struct weston_surface *es, + struct weston_seat *seat); + +static void +shell_surface_focus(struct shell_surface *shsurf) +{ + struct desktop_shell *shell; + struct weston_compositor *compositor; + struct weston_surface *surface; + struct weston_seat *seat; + + shell = shsurf->shell; + compositor = shell->compositor; + surface = shsurf->surface; + + wl_list_for_each(seat, &surface->compositor->seat_list, link) + if (seat->seat.keyboard) { + wl_keyboard_set_focus(seat->seat.keyboard, + &surface->surface); + activate(shell, surface, seat); + } + + weston_compositor_damage_all(compositor); +} + +static void +shell_surface_minimize(struct shell_surface *shsurf) +{ + struct desktop_shell *shell; + struct weston_compositor *compositor; + struct weston_surface *surface; + struct workspace *ws; + struct weston_seat *seat; + struct weston_surface *focus; + + shell = shsurf->shell; + compositor = shell->compositor; + surface = shsurf->surface; + ws = get_current_workspace(shell); + + wl_list_remove(&surface->layer_link); + wl_list_insert(ws->minimized_list.prev, &surface->layer_link); + shsurf->saved_type = shsurf->type; + shsurf->minimized = 1; + + /* Focus next surface in stack */ + wl_list_for_each(seat, &compositor->seat_list, link) + if (seat->seat.keyboard && + seat->keyboard.keyboard.focus == &surface->surface) { + if (!wl_list_empty(&ws->layer.surface_list)) { + focus = container_of(ws->layer.surface_list.next, + struct weston_surface, + layer_link); + shsurf = get_shell_surface(focus); + if (!shsurf) + break; + shell_surface_focus(shsurf); + } else + wl_keyboard_set_focus(seat->seat.keyboard, NULL); + } + + send_surface_data_focused_state(surface); + weston_compositor_damage_all(compositor); +} + +static void +surface_unminimize(struct shell_surface *shsurf, struct workspace *ws) +{ + struct desktop_shell *shell; + struct weston_compositor *compositor; + struct weston_surface *surface; + + shell = shsurf->shell; + compositor = shell->compositor; + surface = shsurf->surface; + + wl_list_remove(&surface->layer_link); + wl_list_insert(ws->layer.surface_list.prev, &surface->layer_link); + shell_surface_focus(shsurf); + send_surface_data_focused_state(surface); + shsurf->minimized = false; + weston_compositor_damage_all(compositor); +} + +static void +shell_surface_unminimize(struct shell_surface *shsurf) +{ + struct weston_surface *surface; + struct workspace *ws = get_current_workspace(shsurf->shell); + + wl_list_for_each(surface, &ws->minimized_list, layer_link) + if (surface == shsurf->surface) { + surface_unminimize(shsurf, ws); + return; + } +} + +static void +surface_data_minimize_handler(struct wl_client *client, + struct wl_resource *resource) { struct shell_surface *shsurf = resource->data; - free(resource); + shell_surface_minimize(shsurf); +} - if (!shsurf) +static void +surface_data_unminimize_handler(struct wl_client *client, + struct wl_resource *resource) +{ + struct shell_surface *shsurf = resource->data; + + shell_surface_unminimize(shsurf); +} + +static void +surface_data_focus_handler(struct wl_client *client, + struct wl_resource *resource) +{ + struct shell_surface *shsurf = resource->data; + + shell_surface_focus(shsurf); +} + +static void +surface_data_close_handler(struct wl_client *client, + struct wl_resource *resource) +{ + struct shell_surface *shsurf; + struct wl_surface *target_surface; + struct wl_client *target_client; + struct desktop_shell *shell; + struct weston_compositor *compositor; + pid_t pid; + + shsurf = resource->data; + target_surface = &shsurf->surface->surface; + shell = shsurf->shell; + compositor = shell->compositor; + + if (!target_surface) return; - shsurf->surface_data = NULL; + wl_signal_emit(&compositor->kill_signal, target_surface); + + target_client = target_surface->resource.client; + wl_client_get_credentials(target_client, &pid, NULL, NULL); + + /* Skip clients that we launched ourselves (the credentials of + * the socketpair is ours) */ + if (pid == getpid()) + return; + + kill(pid, SIGTERM); } static void @@ -1440,9 +1590,26 @@ surface_data_destroy_handler(struct wl_client *client, static const struct surface_data_interface surface_data_implementation = { + surface_data_minimize_handler, + surface_data_unminimize_handler, + surface_data_focus_handler, + surface_data_close_handler, surface_data_destroy_handler }; +static void +surface_data_object_destroy(struct wl_resource *resource) +{ + struct shell_surface *shsurf = resource->data; + + free(resource); + + if (!shsurf) + return; + + shsurf->surface_data = NULL; +} + static int create_surface_data(struct desktop_shell *shell, struct shell_surface *shsurf) { @@ -1523,6 +1690,34 @@ send_surface_data_title(struct weston_surface *surface) } static void +send_surface_data_minimized_state(struct weston_surface *surface) +{ + struct shell_surface *shsurf = get_shell_surface(surface); + + if (shsurf && shsurf->surface_data) + surface_data_send_minimized(shsurf->surface_data, + shsurf->minimized ? 1 : 0); +} + +static void +send_surface_data_focused_state(struct weston_surface *surface) +{ + struct shell_surface *shsurf = get_shell_surface(surface); + struct focus_state *state; + struct workspace *ws; + bool focused = false; + + if (shsurf && shsurf->surface_data) { + ws = get_current_workspace(shsurf->shell); + wl_list_for_each(state, &ws->focus_list, link) + if (state->keyboard_focus == shsurf->surface) + focused = true; + surface_data_send_focused(shsurf->surface_data, + focused); + } +} + +static void shell_surface_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { @@ -2531,6 +2726,14 @@ surface_data_send_all_info(struct desktop_shell *shell) ws = get_current_workspace(shell); wl_list_for_each(surface, &ws->layer.surface_list, layer_link) { + send_surface_data_minimized_state(surface); + send_surface_data_focused_state(surface); + send_surface_data_output_mask(surface); + send_surface_data_title(surface); + } + wl_list_for_each(surface, &ws->minimized_list, layer_link) { + send_surface_data_minimized_state(surface); + send_surface_data_focused_state(surface); send_surface_data_output_mask(surface); send_surface_data_title(surface); } @@ -2869,6 +3072,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es, return; state->keyboard_focus = es; + send_surface_data_focused_state(es); wl_list_remove(&state->surface_destroy_listener.link); wl_signal_add(&es->surface.resource.destroy_signal, &state->surface_destroy_listener); -- 1.7.10.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel