desktop-shell: Make panel and background output dependent
authorBenjamin Franzke <benjaminfranzke@googlemail.com>
Tue, 22 Nov 2011 11:43:52 +0000 (12:43 +0100)
committerBenjamin Franzke <benjaminfranzke@googlemail.com>
Wed, 23 Nov 2011 19:17:54 +0000 (20:17 +0100)
clients/desktop-shell.c
compositor/shell.c
protocol/desktop-shell.xml

index 5b8da64..e313b99 100644 (file)
 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");
@@ -305,6 +342,21 @@ background_draw(struct window *window, int width, int height, const char *path)
 }
 
 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)
 {
        struct rectangle allocation;
@@ -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);
 
index f2d3ef2..a2ffc0d 100644 (file)
 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;
 
@@ -826,79 +833,55 @@ static const struct wl_shell_interface shell_interface = {
 };
 
 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)
index d099925..fef6662 100644 (file)
@@ -2,10 +2,12 @@
 
   <interface name="desktop_shell" version="1">
     <request name="set_background">
+      <arg name="output" type="object" interface="wl_output"/>
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
 
     <request name="set_panel">
+      <arg name="output" type="object" interface="wl_output"/>
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>