diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 5b8da646..e313b990 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -41,18 +41,39 @@ struct desktop { struct display *display; struct desktop_shell *shell; - struct panel *panel; - struct window *background; const char *background_path; struct unlock_dialog *unlock_dialog; struct task unlock_task; + struct wl_list outputs; +}; + +struct surface { + void (*configure)(void *data, + struct desktop_shell *desktop_shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height); }; struct panel { + struct surface base; struct window *window; struct window *menu; }; +struct background { + struct surface base; + struct window *window; +}; + +struct output { + struct wl_output *output; + struct wl_list link; + + struct panel *panel; + struct background *background; +}; + struct panel_item { struct item *item; struct panel *panel; @@ -113,6 +134,7 @@ show_menu(struct panel *panel, struct input *input) display = window_get_display(panel->window); panel->menu = window_create_transient(display, panel->window, x - 10, y - 10, width, height); + window_set_user_data(panel->menu, panel); window_draw(panel->menu); window_flush(panel->menu); @@ -234,6 +256,20 @@ panel_button_handler(struct window *window, } } +static void +panel_configure(void *data, + struct desktop_shell *desktop_shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height) +{ + struct panel *panel = + window_get_user_data(wl_surface_get_user_data(surface)); + + window_set_child_size(panel->window, width, 32); + window_schedule_redraw(panel->window); +} + static struct panel * panel_create(struct display *display) { @@ -242,6 +278,7 @@ panel_create(struct display *display) panel = malloc(sizeof *panel); memset(panel, 0, sizeof *panel); + panel->base.configure = panel_configure; panel->window = window_create(display, 0, 0); window_set_title(panel->window, "panel"); @@ -304,6 +341,21 @@ background_draw(struct window *window, int width, int height, const char *path) window_flush(window); } +static void +background_configure(void *data, + struct desktop_shell *desktop_shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height) +{ + struct desktop *desktop = data; + struct background *background = + window_get_user_data(wl_surface_get_user_data(surface)); + + background_draw(background->window, + width, height, desktop->background_path); +} + static void unlock_dialog_draw(struct unlock_dialog *dialog) { @@ -454,15 +506,10 @@ desktop_shell_configure(void *data, struct wl_surface *surface, int32_t width, int32_t height) { - struct desktop *desktop = data; + struct surface *s = + window_get_user_data(wl_surface_get_user_data(surface)); - if (surface == window_get_wl_surface(desktop->panel->window)) { - window_set_child_size(desktop->panel->window, width, 32); - window_schedule_redraw(desktop->panel->window); - } else if (surface == window_get_wl_surface(desktop->background)) { - background_draw(desktop->background, - width, height, desktop->background_path); - } + s->configure(data, desktop_shell, time, edges, surface, width, height); } static void @@ -482,6 +529,38 @@ static const struct desktop_shell_listener listener = { desktop_shell_prepare_lock_surface }; +static struct background * +background_create(struct desktop *desktop) +{ + struct background *background; + + background = malloc(sizeof *background); + memset(background, 0, sizeof *background); + + background->base.configure = background_configure; + background->window = window_create(desktop->display, 0, 0); + window_set_decoration(background->window, 0); + window_set_custom(background->window); + window_set_user_data(background->window, background); + + return background; +} + +static void +create_output(struct desktop *desktop, uint32_t id) +{ + struct output *output; + + output = calloc(1, sizeof *output); + if (!output) + return; + + output->output = wl_display_bind(display_get_display(desktop->display), + id, &wl_output_interface); + + wl_list_insert(&desktop->outputs, &output->link); +} + static void global_handler(struct wl_display *display, uint32_t id, const char *interface, uint32_t version, void *data) @@ -492,6 +571,8 @@ global_handler(struct wl_display *display, uint32_t id, desktop->shell = wl_display_bind(display, id, &desktop_shell_interface); desktop_shell_add_listener(desktop->shell, &listener, desktop); + } else if (!strcmp(interface, "wl_output")) { + create_output(desktop, id); } } @@ -499,13 +580,17 @@ static void launcher_section_done(void *data) { struct desktop *desktop = data; + struct output *output; if (key_launcher_icon == NULL || key_launcher_path == NULL) { fprintf(stderr, "invalid launcher section\n"); return; } - panel_add_item(desktop->panel, key_launcher_icon, key_launcher_path); + wl_list_for_each(output, &desktop->outputs, link) + panel_add_item(output->panel, + key_launcher_icon, key_launcher_path); + free(key_launcher_icon); key_launcher_icon = NULL; free(key_launcher_path); @@ -516,8 +601,10 @@ int main(int argc, char *argv[]) { struct desktop desktop = { 0 }; char *config_file; + struct output *output; desktop.unlock_task.run = unlock_dialog_finish; + wl_list_init(&desktop.outputs); desktop.display = display_create(&argc, &argv, NULL); if (desktop.display == NULL) { @@ -531,7 +618,18 @@ int main(int argc, char *argv[]) wl_display_add_global_listener(display_get_display(desktop.display), global_handler, &desktop); - desktop.panel = panel_create(desktop.display); + wl_list_for_each(output, &desktop.outputs, link) { + struct wl_surface *surface; + + output->panel = panel_create(desktop.display); + surface = window_get_wl_surface(output->panel->window); + desktop_shell_set_panel(desktop.shell, output->output, surface); + + output->background = background_create(&desktop); + surface = window_get_wl_surface(output->background->window); + desktop_shell_set_background(desktop.shell, + output->output, surface); + } config_file = config_file_path("wayland-desktop-shell.ini"); parse_config_file(config_file, @@ -539,15 +637,7 @@ int main(int argc, char *argv[]) &desktop); free(config_file); - desktop_shell_set_panel(desktop.shell, - window_get_wl_surface(desktop.panel->window)); - - desktop.background = window_create(desktop.display, 0, 0); - window_set_decoration(desktop.background, 0); - window_set_custom(desktop.background); desktop.background_path = key_background_image; - desktop_shell_set_background(desktop.shell, - window_get_wl_surface(desktop.background)); signal(SIGCHLD, sigchild_handler); diff --git a/compositor/shell.c b/compositor/shell.c index f2d3ef22..a2ffc0df 100644 --- a/compositor/shell.c +++ b/compositor/shell.c @@ -39,10 +39,6 @@ struct wl_shell { struct wlsc_compositor *compositor; struct wlsc_shell shell; - struct wlsc_surface *panel; - struct wl_listener panel_listener; - struct wlsc_surface *background; - struct wl_listener background_listener; struct { struct wlsc_process process; @@ -56,6 +52,9 @@ struct wl_shell { struct wlsc_surface *lock_surface; struct wl_listener lock_surface_listener; struct wl_list hidden_surface_list; + + struct wl_list backgrounds; + struct wl_list panels; }; enum shell_surface_type { @@ -71,10 +70,14 @@ enum shell_surface_type { }; struct shell_surface { + struct wlsc_surface *surface; struct wl_listener destroy_listener; enum shell_surface_type type; int32_t saved_x, saved_y; + + struct wlsc_output *output; + struct wl_list link; }; struct wlsc_move_grab { @@ -87,6 +90,7 @@ static void destroy_shell_surface(struct shell_surface *priv) { wl_list_remove(&priv->destroy_listener.link); + wl_list_remove(&priv->link); free(priv); } @@ -116,6 +120,9 @@ get_shell_surface(struct wlsc_surface *surface) &priv->destroy_listener.link); surface->shell_priv = priv; + priv->surface = surface; + /* init link so its safe to always remove it in destroy_shell_surface */ + wl_list_init(&priv->link); priv->type = SHELL_SURFACE_NORMAL; @@ -825,80 +832,56 @@ static const struct wl_shell_interface shell_interface = { shell_set_fullscreen }; -static void -handle_background_surface_destroy(struct wl_listener *listener, - struct wl_resource *resource, uint32_t time) -{ - struct wl_shell *shell = - container_of(listener, struct wl_shell, background_listener); - - fprintf(stderr, "background surface gone\n"); - shell->background = NULL; -} - static void desktop_shell_set_background(struct wl_client *client, struct wl_resource *resource, + struct wl_resource *output_resource, struct wl_resource *surface_resource) { struct wl_shell *shell = resource->data; struct wlsc_surface *surface = surface_resource->data; - struct wlsc_output *output = - container_of(shell->compositor->output_list.next, - struct wlsc_output, link); struct shell_surface *priv; - shell->background = surface_resource->data; - shell->background_listener.func = handle_background_surface_destroy; - wl_list_insert(&surface_resource->destroy_listener_list, - &shell->background_listener.link); - priv = get_shell_surface(surface); priv->type = SHELL_SURFACE_BACKGROUND; + priv->output = output_resource->data; + + wl_list_insert(&shell->backgrounds, &priv->link); + + surface->x = priv->output->x; + surface->y = priv->output->y; wl_resource_post_event(resource, DESKTOP_SHELL_CONFIGURE, wlsc_compositor_get_time(), 0, surface, - output->current->width, - output->current->height); -} - -static void -handle_panel_surface_destroy(struct wl_listener *listener, - struct wl_resource *resource, uint32_t time) -{ - struct wl_shell *shell = - container_of(listener, struct wl_shell, panel_listener); - - fprintf(stderr, "panel surface gone\n"); - shell->panel = NULL; + priv->output->current->width, + priv->output->current->height); } static void desktop_shell_set_panel(struct wl_client *client, struct wl_resource *resource, + struct wl_resource *output_resource, struct wl_resource *surface_resource) { struct wl_shell *shell = resource->data; - struct wlsc_output *output = - container_of(shell->compositor->output_list.next, - struct wlsc_output, link); + struct wlsc_surface *surface = surface_resource->data; struct shell_surface *priv; - shell->panel = surface_resource->data; + priv = get_shell_surface(surface); + priv->type = SHELL_SURFACE_PANEL; + priv->output = output_resource->data; - shell->panel_listener.func = handle_panel_surface_destroy; - wl_list_insert(&surface_resource->destroy_listener_list, - &shell->panel_listener.link); + wl_list_insert(&shell->panels, &priv->link); - priv = get_shell_surface(shell->panel); - priv->type = SHELL_SURFACE_PANEL; + surface->x = priv->output->x; + surface->y = priv->output->y; wl_resource_post_event(resource, DESKTOP_SHELL_CONFIGURE, wlsc_compositor_get_time(), 0, surface_resource, - output->current->width, - output->current->height); + priv->output->current->width, + priv->output->current->height); } static void @@ -939,12 +922,15 @@ static void resume_desktop(struct wl_shell *shell) { struct wlsc_surface *surface; + struct shell_surface *background; wl_list_for_each(surface, &shell->hidden_surface_list, link) wlsc_surface_configure(surface, surface->x, surface->y, surface->width, surface->height); - wl_list_insert_list(shell->background->link.prev, + background = container_of(shell->backgrounds.prev, + struct shell_surface, link); + wl_list_insert_list(background->surface->link.prev, &shell->hidden_surface_list); wl_list_init(&shell->hidden_surface_list); @@ -976,21 +962,23 @@ static void move_binding(struct wl_input_device *device, uint32_t time, uint32_t key, uint32_t button, uint32_t state, void *data) { - struct wl_shell *shell = data; struct wlsc_surface *surface = (struct wlsc_surface *) device->pointer_focus; struct shell_surface *priv; - priv = get_shell_surface(surface); - - if (surface == NULL || - priv->type == SHELL_SURFACE_FULLSCREEN) - return; - if (surface == shell->panel) - return; - if (surface == shell->background) + if (surface == NULL) return; + priv = get_shell_surface(surface); + switch (priv->type) { + case SHELL_SURFACE_PANEL: + case SHELL_SURFACE_BACKGROUND: + case SHELL_SURFACE_FULLSCREEN: + return; + default: + break; + } + wlsc_surface_move(surface, (struct wlsc_input_device *) device, time); } @@ -998,7 +986,6 @@ static void resize_binding(struct wl_input_device *device, uint32_t time, uint32_t key, uint32_t button, uint32_t state, void *data) { - struct wl_shell *shell = data; struct wlsc_surface *surface = (struct wlsc_surface *) device->pointer_focus; struct wl_resource *resource; @@ -1006,14 +993,18 @@ resize_binding(struct wl_input_device *device, uint32_t time, int32_t x, y; struct shell_surface *priv; - priv = get_shell_surface(surface); - - if (surface == NULL || - priv->type == SHELL_SURFACE_FULLSCREEN) - if (surface == shell->panel) - return; - if (surface == shell->background) + if (surface == NULL) return; + + priv = get_shell_surface(surface); + switch (priv->type) { + case SHELL_SURFACE_PANEL: + case SHELL_SURFACE_BACKGROUND: + case SHELL_SURFACE_FULLSCREEN: + return; + default: + break; + } x = device->grab_x - surface->x; y = device->grab_y - surface->y; @@ -1065,11 +1056,14 @@ activate(struct wlsc_shell *base, struct wlsc_surface *es, /* already put on top */ break; default: - if (shell->panel && !shell->locked) { + if (!shell->locked) { /* bring panel back to top */ - wl_list_remove(&shell->panel->link); - wl_list_insert(&compositor->surface_list, - &shell->panel->link); + struct shell_surface *panel; + wl_list_for_each(panel, &shell->panels, link) { + wl_list_remove(&panel->surface->link); + wl_list_insert(&compositor->surface_list, + &panel->surface->link); + } } } } @@ -1188,10 +1182,14 @@ map(struct wlsc_shell *base, break; default: /* everything else just below the panel */ - if (shell->panel) - wl_list_insert(&shell->panel->link, &surface->link); - else + if (!wl_list_empty(&shell->panels)) { + struct shell_surface *panel = + container_of(shell->panels.prev, + struct shell_surface, link); + wl_list_insert(&panel->surface->link, &surface->link); + } else { wl_list_insert(list, &surface->link); + } } if (priv->type == SHELL_SURFACE_TOPLEVEL) { @@ -1348,6 +1346,8 @@ shell_init(struct wlsc_compositor *ec) shell->shell.set_selection_focus = wlsc_selection_set_focus; wl_list_init(&shell->hidden_surface_list); + wl_list_init(&shell->backgrounds); + wl_list_init(&shell->panels); if (wl_display_add_global(ec->wl_display, &wl_shell_interface, shell, bind_shell) == NULL) diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml index d099925f..fef66627 100644 --- a/protocol/desktop-shell.xml +++ b/protocol/desktop-shell.xml @@ -2,10 +2,12 @@ + +