We draw a taskbar surface in desktop-shell, extend the
desktop-shell protocol to send it to the compositor, and
the compositor will draw it in a new taskbar layer at the
bottom.

Signed-off-by: Manuel Bachmann <manuel.bachm...@open.eurogiciel.org>
---
 clients/desktop-shell.c    |  144 ++++++++++++++++++++++++++++++++++++++++++++
 desktop-shell/shell.c      |   53 +++++++++++++++-
 desktop-shell/shell.h      |    1 +
 protocol/desktop-shell.xml |    5 ++
 4 files changed, 201 insertions(+), 2 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index a0c6b6d..c341a91 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -85,6 +85,16 @@ struct panel {
        uint32_t color;
 };
 
+struct taskbar {
+       struct surface base;
+       struct window *window;
+       struct widget *widget;
+       struct wl_list handler_list;
+       struct desktop *desktop;
+       int painted;
+       uint32_t color;
+};
+
 struct background {
        struct surface base;
        struct window *window;
@@ -102,6 +112,7 @@ struct output {
        struct wl_list link;
 
        struct panel *panel;
+       struct taskbar *taskbar;
        struct background *background;
 };
 
@@ -123,6 +134,16 @@ struct panel_clock {
        int clock_fd;
 };
 
+struct taskbar_handler {
+       struct widget *widget;
+       struct taskbar *taskbar;
+       cairo_surface_t *icon;
+       int focused, pressed;
+       char *title;
+       int state;
+       struct wl_list link;
+};
+
 struct unlock_dialog {
        struct window *window;
        struct widget *widget;
@@ -173,6 +194,8 @@ is_desktop_painted(struct desktop *desktop)
        wl_list_for_each(output, &desktop->outputs, link) {
                if (output->panel && !output->panel->painted)
                        return 0;
+               if (output->taskbar && !output->taskbar->painted)
+                       return 0;
                if (output->background && !output->background->painted)
                        return 0;
        }
@@ -566,6 +589,119 @@ panel_create(struct desktop *desktop)
        return panel;
 }
 
+static void
+taskbar_redraw_handler(struct widget *widget, void *data)
+{
+       cairo_surface_t *surface;
+       cairo_t *cr;
+       struct taskbar *taskbar = data;
+
+       cr = widget_cairo_create(taskbar->widget);
+       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+       set_hex_color(cr, taskbar->color);
+       cairo_paint(cr);
+
+       cairo_destroy(cr);
+       surface = window_get_surface(taskbar->window);
+       cairo_surface_destroy(surface);
+       taskbar->painted = 1;
+       check_desktop_ready(taskbar->window);
+}
+
+static void
+taskbar_resize_handler(struct widget *widget,
+                    int32_t width, int32_t height, void *data)
+{
+       struct taskbar_handler *handler;
+       struct taskbar *taskbar = data;
+       cairo_t *cr;
+       cairo_text_extents_t extents;
+       int x, y, w, h;
+       
+       x = 10;
+       y = 16;
+       wl_list_for_each(handler, &taskbar->handler_list, link) {
+               cr = cairo_create (handler->icon);
+               cairo_text_extents (cr, handler->title, &extents);
+
+               w = cairo_image_surface_get_width(handler->icon) + 
extents.width + 8;
+               h = cairo_image_surface_get_height(handler->icon);
+               widget_set_allocation(handler->widget,
+                                     x, y - h / 2, w + 1, h + 1);
+               x += w + 10;
+
+               cairo_destroy (cr);
+       }
+}
+
+static void
+taskbar_configure(void *data,
+               struct desktop_shell *desktop_shell,
+               uint32_t edges, struct window *window,
+               int32_t width, int32_t height)
+{
+       struct surface *surface = window_get_user_data(window);
+       struct taskbar *taskbar = container_of(surface, struct taskbar, base);
+
+       window_schedule_resize(taskbar->window, width, 32);
+}
+
+static void
+taskbar_destroy_handler(struct taskbar_handler *handler)
+{
+       free(handler->title);
+
+       cairo_surface_destroy(handler->icon);
+
+       widget_destroy(handler->widget);
+       wl_list_remove(&handler->link);
+
+       free(handler);
+}
+
+static void
+taskbar_destroy(struct taskbar *taskbar)
+{
+       struct taskbar_handler *tmp;
+       struct taskbar_handler *handler;
+
+       wl_list_for_each_safe(handler, tmp, &taskbar->handler_list, link) {
+               taskbar_destroy_handler(handler);
+       }
+
+       widget_destroy(taskbar->widget);
+       window_destroy(taskbar->window);
+
+       free(taskbar);
+}
+
+static struct taskbar *
+taskbar_create(struct desktop *desktop)
+{
+       struct taskbar *taskbar;
+       struct weston_config_section *s;
+
+       taskbar = xzalloc(sizeof *taskbar);
+
+       taskbar->base.configure = taskbar_configure;
+       taskbar->desktop = desktop;
+       taskbar->window = window_create_custom(desktop->display);
+       taskbar->widget = window_add_widget(taskbar->window, taskbar);
+       wl_list_init(&taskbar->handler_list);
+
+       window_set_title(taskbar->window, "taskbar");
+       window_set_user_data(taskbar->window, taskbar);
+
+       widget_set_redraw_handler(taskbar->widget, taskbar_redraw_handler);
+       widget_set_resize_handler(taskbar->widget, taskbar_resize_handler);
+
+       s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
+       weston_config_section_get_uint(s, "taskbar-color",
+                                      &taskbar->color, 0xaabbbbbb);
+
+       return taskbar;
+}
+
 static cairo_surface_t *
 load_icon_or_fallback(const char *icon)
 {
@@ -1128,6 +1264,7 @@ output_destroy(struct output *output)
 {
        background_destroy(output->background);
        panel_destroy(output->panel);
+       taskbar_destroy(output->taskbar);
        wl_output_destroy(output->output);
        wl_list_remove(&output->link);
 
@@ -1158,6 +1295,7 @@ output_handle_geometry(void *data,
        struct output *output = data;
 
        window_set_buffer_transform(output->panel->window, transform);
+       window_set_buffer_transform(output->taskbar->window, transform);
        window_set_buffer_transform(output->background->window, transform);
 }
 
@@ -1185,6 +1323,7 @@ output_handle_scale(void *data,
        struct output *output = data;
 
        window_set_buffer_scale(output->panel->window, scale);
+       window_set_buffer_scale(output->taskbar->window, scale);
        window_set_buffer_scale(output->background->window, scale);
 }
 
@@ -1205,6 +1344,11 @@ output_init(struct output *output, struct desktop 
*desktop)
        desktop_shell_set_panel(desktop->shell,
                                output->output, surface);
 
+       output->taskbar = taskbar_create(desktop);
+       surface = window_get_wl_surface(output->taskbar->window);
+       desktop_shell_set_taskbar(desktop->shell,
+                               output->output, surface);
+
        output->background = background_create(desktop);
        surface = window_get_wl_surface(output->background->window);
        desktop_shell_set_background(desktop->shell,
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 7811962..7d7efaa 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -73,7 +73,7 @@ enum shell_surface_type {
  *  • Lock layer (only ever displayed on its own)
  *  • Cursor layer
  *  • Fullscreen layer
- *  • Panel layer
+ *  • Panel layer - Taskbar layer
  *  • Input panel layer
  *  • Workspace layers
  *  • Background layer
@@ -3747,6 +3747,53 @@ desktop_shell_set_panel(struct wl_client *client,
 }
 
 static void
+taskbar_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+       struct desktop_shell *shell = es->configure_private;
+       struct weston_view *view;
+
+       view = container_of(es->views.next, struct weston_view, surface_link);
+
+       configure_static_view(view, &shell->taskbar_layer);
+
+       weston_view_set_position(view, 0, view->output->height
+                                       - view->surface->height);
+}
+
+static void
+desktop_shell_set_taskbar(struct wl_client *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *output_resource,
+                              struct wl_resource *surface_resource)
+{
+       struct desktop_shell *shell = wl_resource_get_user_data(resource);
+       struct weston_surface *surface =
+               wl_resource_get_user_data(surface_resource);
+       struct weston_view *view, *next;
+
+       if (surface->configure) {
+               wl_resource_post_error(surface_resource,
+                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
+                                      "surface role already assigned");
+               return;
+       }
+
+       wl_list_for_each_safe(view, next, &surface->views, surface_link)
+               weston_view_destroy(view);
+       view = weston_view_create(surface);
+
+       /* send post-creation configure request to desktop-shell taskbar */
+       surface->configure = taskbar_configure;
+       surface->configure_private = shell;
+       surface->output = wl_resource_get_user_data(output_resource);
+       view->output = surface->output;
+       desktop_shell_send_configure(resource, 0,
+                                    surface_resource,
+                                    surface->output->width,
+                                    surface->output->height);
+}
+
+static void
 lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
 {
        struct desktop_shell *shell = surface->configure_private;
@@ -3865,6 +3912,7 @@ desktop_shell_desktop_ready(struct wl_client *client,
 static const struct desktop_shell_interface desktop_shell_implementation = {
        desktop_shell_set_background,
        desktop_shell_set_panel,
+       desktop_shell_set_taskbar,
        desktop_shell_set_lock_surface,
        desktop_shell_unlock,
        desktop_shell_set_grab_surface,
@@ -5859,7 +5907,8 @@ module_init(struct weston_compositor *ec,
        ec->shell_interface.set_title = set_title;
 
        weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
-       weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
+       weston_layer_init(&shell->taskbar_layer, &shell->fullscreen_layer.link);
+       weston_layer_init(&shell->panel_layer, &shell->taskbar_layer.link);
        weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
        weston_layer_init(&shell->lock_layer, NULL);
        weston_layer_init(&shell->input_panel_layer, NULL);
diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h
index 48ac250..104e621 100644
--- a/desktop-shell/shell.h
+++ b/desktop-shell/shell.h
@@ -124,6 +124,7 @@ struct desktop_shell {
 
        struct weston_layer fullscreen_layer;
        struct weston_layer panel_layer;
+       struct weston_layer taskbar_layer;
        struct weston_layer background_layer;
        struct weston_layer lock_layer;
        struct weston_layer input_panel_layer;
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index 65e44a7..3ae5d33 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -17,6 +17,11 @@
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
 
+    <request name="set_taskbar">
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
     <request name="set_lock_surface">
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
-- 
1.7.10.4

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to