This patch uses the special surface_data interface to send surface_data to the
shell. The shell then uses this information to render a window list in the 
panel.

---

v5:

* Removed unneeded calls in map(). The call to send_output_mask() in
  weston_surface_update_output_mask() takes care of sending the output_mask.
  The calls in map() were left over from before the send_output_mask function
  pointer existed.
* Changed inital value of the title string in desktop-shell

 clients/desktop-shell.c | 504 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/compositor.c        |   2 +
 src/compositor.h        |   1 +
 src/shell.c             | 182 +++++++++++++++++
 4 files changed, 671 insertions(+), 18 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 588dc1c..8718c82 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -44,6 +44,8 @@
 
 #include "desktop-shell-client-protocol.h"
 
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
 extern char **environ; /* defined by libc */
 
 struct desktop {
@@ -52,36 +54,55 @@ struct desktop {
        struct unlock_dialog *unlock_dialog;
        struct task unlock_task;
        struct wl_list outputs;
+       uint32_t output_count;
 
        struct window *grab_window;
        struct widget *grab_widget;
 
        enum cursor_type grab_cursor;
+
+       struct surface_data_manager *surface_data_manager;
 };
 
 struct surface {
+       struct wl_list item_list;
+       struct surface_data *surface_data;
+       uint32_t output_mask;
+       char *title;
+};
+
+struct resize {
        void (*configure)(void *data,
                          struct desktop_shell *desktop_shell,
                          uint32_t edges, struct window *window,
                          int32_t width, int32_t height);
 };
 
+struct rgba {
+       float r, g, b, a;
+};
+
 struct panel {
-       struct surface base;
+       struct resize base;
        struct window *window;
        struct widget *widget;
        struct wl_list launcher_list;
+       struct wl_list window_list;
+       struct rectangle window_list_rect;
+       uint32_t surface_count;
+       struct rgba focused_item;
        struct panel_clock *clock;
 };
 
 struct background {
-       struct surface base;
+       struct resize base;
        struct window *window;
        struct widget *widget;
 };
 
 struct output {
        struct wl_output *output;
+       uint32_t id;
        struct wl_list link;
 
        struct panel *panel;
@@ -99,6 +120,16 @@ struct panel_launcher {
        struct wl_array argv;
 };
 
+struct list_item {
+       struct surface *surface;
+       struct widget *widget;
+       struct panel *panel;
+       cairo_surface_t *icon;
+       int focused, pressed;
+       struct wl_list link;
+       struct wl_list surface_link;
+};
+
 struct panel_clock {
        struct widget *widget;
        struct panel *panel;
@@ -249,6 +280,15 @@ set_hex_color(cairo_t *cr, uint32_t color)
 }
 
 static void
+get_hex_color_rgba(uint32_t color, float *r, float *g, float *b, float *a)
+{
+       *r = ((color >> 16) & 0xff) / 255.0;
+       *g = ((color >>  8) & 0xff) / 255.0;
+       *b = ((color >>  0) & 0xff) / 255.0;
+       *a = ((color >> 24) & 0xff) / 255.0;
+}
+
+static void
 panel_redraw_handler(struct widget *widget, void *data)
 {
        cairo_surface_t *surface;
@@ -337,7 +377,7 @@ panel_clock_redraw_handler(struct widget *widget, void 
*data)
 
        surface = window_get_surface(clock->panel->window);
        cr = cairo_create(surface);
-       cairo_select_font_face(cr, "sans",
+       cairo_select_font_face(cr, "helvetica",
                               CAIRO_FONT_SLANT_NORMAL,
                               CAIRO_FONT_WEIGHT_NORMAL);
        cairo_set_font_size(cr, 14);
@@ -411,15 +451,49 @@ panel_button_handler(struct widget *widget,
 }
 
 static void
+panel_window_list_schedule_redraw(struct panel *panel)
+{
+       struct list_item *item;
+       float x, y, w, h;
+       float item_width, padding;
+
+       /* If there are no window list items, redraw the panel to clear it */
+       if (wl_list_empty(&panel->window_list)) {
+               widget_schedule_redraw(panel->widget);
+               return;
+       }
+
+       item_width = ((float) panel->window_list_rect.width /
+                                                       panel->surface_count);
+       padding = MIN(item_width * 0.1f, 10.0f);
+
+       x = panel->window_list_rect.x + padding;
+       y = 16;
+       w = MIN(item_width - padding, 200);
+       h = 24;
+
+       wl_list_for_each(item, &panel->window_list, link) {
+               widget_set_allocation(item->widget, x, y - h / 2, w + 1, h + 1);
+               x += w + padding;
+               widget_schedule_redraw(item->widget);
+       }
+}
+
+static void
 panel_resize_handler(struct widget *widget,
                     int32_t width, int32_t height, void *data)
 {
        struct panel_launcher *launcher;
+       struct rectangle launcher_rect;
+       struct rectangle clock_rect;
        struct panel *panel = data;
        int x, y, w, h;
-       
+
        x = 10;
        y = 16;
+
+       launcher_rect.x = x;
+
        wl_list_for_each(launcher, &panel->launcher_list, link) {
                w = cairo_image_surface_get_width(launcher->icon);
                h = cairo_image_surface_get_height(launcher->icon);
@@ -427,12 +501,25 @@ panel_resize_handler(struct widget *widget,
                                      x, y - h / 2, w + 1, h + 1);
                x += w + 10;
        }
-       h=20;
+
+       launcher_rect.width = x - launcher_rect.x;
+
        w=170;
+       h=20;
 
        if (panel->clock)
                widget_set_allocation(panel->clock->widget,
                                      width - w - 8, y - h / 2, w + 1, h + 1);
+
+       widget_get_allocation(panel->clock->widget, &clock_rect);
+
+       panel->window_list_rect.x = launcher_rect.x + launcher_rect.width;
+       panel->window_list_rect.y = 2;
+       panel->window_list_rect.width = width -
+                                       panel->window_list_rect.x -
+                                       (clock_rect.width + 20);
+       panel->window_list_rect.height = 28;
+       panel_window_list_schedule_redraw(panel);
 }
 
 static void
@@ -441,12 +528,31 @@ panel_configure(void *data,
                uint32_t edges, struct window *window,
                int32_t width, int32_t height)
 {
-       struct surface *surface = window_get_user_data(window);
+       struct resize *surface = window_get_user_data(window);
        struct panel *panel = container_of(surface, struct panel, base);
 
        window_schedule_resize(panel->window, width, 32);
 }
 
+static void
+panel_set_list_item_focus_color(struct panel *panel)
+{
+       float r, g, b, a;
+
+       /* Consider panel color when choosing item highlight color */
+       get_hex_color_rgba(key_panel_color, &r, &b, &g, &a);
+       if (r += 0.2, g += 0.2, b += 0.2, r > 1.0 || g > 1.0 || b > 1.0) {
+               panel->focused_item.r = 0.6;
+               panel->focused_item.g = 0.6;
+               panel->focused_item.b = 0.6;
+       } else {
+               panel->focused_item.r = r;
+               panel->focused_item.g = g;
+               panel->focused_item.b = b;
+       }
+       panel->focused_item.a = 0.75;
+}
+
 static struct panel *
 panel_create(struct display *display)
 {
@@ -459,6 +565,7 @@ panel_create(struct display *display)
        panel->window = window_create_custom(display);
        panel->widget = window_add_widget(panel->window, panel);
        wl_list_init(&panel->launcher_list);
+       wl_list_init(&panel->window_list);
 
        window_set_title(panel->window, "panel");
        window_set_user_data(panel->window, panel);
@@ -466,7 +573,9 @@ panel_create(struct display *display)
        widget_set_redraw_handler(panel->widget, panel_redraw_handler);
        widget_set_resize_handler(panel->widget, panel_resize_handler);
        widget_set_button_handler(panel->widget, panel_button_handler);
-       
+
+       panel->surface_count = 0;
+       panel_set_list_item_focus_color(panel);
        panel_add_clock(panel);
 
        return panel;
@@ -475,18 +584,21 @@ panel_create(struct display *display)
 static cairo_surface_t *
 load_icon_or_fallback(const char *icon)
 {
-       cairo_surface_t *surface = cairo_image_surface_create_from_png(icon);
+       cairo_surface_t *surface;
        cairo_t *cr;
-
-       if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS)
-               return surface;
-
-       cairo_surface_destroy(surface);
-       fprintf(stderr, "ERROR loading icon from file '%s'\n", icon);
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+       if (icon) {
+               surface = cairo_image_surface_create_from_png(icon);
+               if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS)
+                       return surface;
+
+               cairo_surface_destroy(surface);
+               fprintf(stderr, "ERROR loading icon from file '%s'\n", icon);
+       }
+#endif
 
        /* draw fallback icon */
-       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                            20, 20);
+       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 20, 20);
        cr = cairo_create(surface);
 
        cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
@@ -810,7 +922,7 @@ desktop_shell_configure(void *data,
                        int32_t width, int32_t height)
 {
        struct window *window = wl_surface_get_user_data(surface);
-       struct surface *s = window_get_user_data(window);
+       struct resize *s = window_get_user_data(window);
 
        s->configure(data, desktop_shell, edges, window, width, height);
 }
@@ -885,6 +997,352 @@ static const struct desktop_shell_listener listener = {
        desktop_shell_grab_cursor
 };
 
+static void
+panel_list_item_redraw_handler(struct widget *widget, void *data)
+{
+       cairo_t *cr;
+       cairo_surface_t *surface;
+       struct list_item *item = data;
+       struct rectangle rect;
+       cairo_text_extents_t extents;
+       cairo_font_extents_t font_extents;
+       int icon_width;
+       unsigned int dots = 3;
+       char title[128];
+
+       widget_get_allocation(widget, &rect);
+       if (rect.width == 0)
+               return;
+
+       surface = window_get_surface(item->panel->window);
+       cr = cairo_create(surface);
+
+       if (item->focused) {
+               cairo_set_source_rgba(cr,
+                                       item->panel->focused_item.r,
+                                       item->panel->focused_item.g,
+                                       item->panel->focused_item.b,
+                                       item->panel->focused_item.a);
+               cairo_move_to(cr, rect.x, rect.y);
+               cairo_line_to(cr, rect.x + rect.width, rect.y);
+               cairo_line_to(cr, rect.x + rect.width, rect.y + rect.height);
+               cairo_line_to(cr, rect.x, rect.y + rect.height);
+               cairo_line_to(cr, rect.x, rect.y);
+               cairo_fill(cr);
+       }
+
+       icon_width = cairo_image_surface_get_width(item->icon);
+       if (rect.width > icon_width * 2) {
+               cairo_set_source_surface(cr, item->icon,
+                                        rect.x, rect.y);
+               cairo_paint(cr);
+       } else
+               icon_width = 0;
+
+       strcpy(title, item->surface->title);
+       cairo_select_font_face(cr, "helvetica",
+                              CAIRO_FONT_SLANT_NORMAL,
+                              CAIRO_FONT_WEIGHT_NORMAL);
+       cairo_set_font_size(cr, 14);
+       cairo_text_extents(cr, title, &extents);
+
+       /* If the string is too long, clip text to button width */
+       while (extents.width > (rect.width - (10 + icon_width))) {
+               title[strlen(title) - 1] = '\0';
+               cairo_text_extents(cr, title, &extents);
+               if (extents.width <= 0) {
+                       title[0] = '\0';
+                       break;
+               }
+       }
+
+       /* If the text is clipped, add an ellipsis */
+       if (strlen(title) < dots)
+               dots = strlen(title) + 1;
+       if (strlen(title) != strlen(item->surface->title))
+               while (dots-- > 0)
+                       title[strlen(title) - dots] = '.';
+
+       cairo_font_extents (cr, &font_extents);
+       cairo_move_to(cr, rect.x + 10 + icon_width,
+                     rect.y + 3 * (rect.height >> 2) + 1);
+       cairo_set_source_rgb(cr, 0, 0, 0);
+       cairo_show_text(cr, title);
+       cairo_move_to(cr, rect.x + 9 + icon_width,
+                     rect.y + 3 * (rect.height >> 2));
+       if (item->focused)
+               cairo_set_source_rgb(cr, 1, 1, 1);
+       else
+               cairo_set_source_rgb(cr, 0.85, 0.85, 0.85);
+       cairo_show_text(cr, title);
+       cairo_destroy(cr);
+}
+
+static int
+panel_list_item_motion_handler(struct widget *widget, struct input *input,
+                             uint32_t time, float x, float y, void *data)
+{
+       struct list_item *item = data;
+
+       widget_set_tooltip(widget, basename((char *)item->surface->title), x, 
y);
+
+       return CURSOR_LEFT_PTR;
+}
+
+static int
+panel_list_item_enter_handler(struct widget *widget, struct input *input,
+                            float x, float y, void *data)
+{
+       struct list_item *item = data;
+
+       item->focused = 1;
+       widget_schedule_redraw(widget);
+
+       return CURSOR_LEFT_PTR;
+}
+
+static void
+panel_list_item_leave_handler(struct widget *widget,
+                            struct input *input, void *data)
+{
+       struct list_item *item = data;
+
+       item->focused = 0;
+       widget_destroy_tooltip(widget);
+       widget_schedule_redraw(widget);
+}
+
+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)
+{
+       widget_schedule_redraw(widget);
+       /* TODO: Toggle minimize */
+}
+
+static struct list_item *
+panel_list_item_add(struct panel *panel, const char *icon, const char *text)
+{
+       struct list_item *item;
+       item = malloc(sizeof *item);
+       memset(item, 0, sizeof *item);
+
+       item->icon = load_icon_or_fallback(icon);
+
+       item->panel = panel;
+       wl_list_insert(panel->window_list.prev, &item->link);
+       panel->surface_count++;
+
+       item->widget = widget_add_widget(panel->widget, item);
+       widget_set_enter_handler(item->widget, panel_list_item_enter_handler);
+       widget_set_leave_handler(item->widget, panel_list_item_leave_handler);
+       widget_set_button_handler(item->widget, panel_list_item_button_handler);
+       widget_set_redraw_handler(item->widget, panel_list_item_redraw_handler);
+       widget_set_motion_handler(item->widget, panel_list_item_motion_handler);
+
+       return item;
+}
+
+static void
+panel_list_item_remove(struct list_item *item)
+{
+       item->panel->surface_count--;
+       wl_list_remove(&item->link);
+       wl_list_remove(&item->surface_link);
+       widget_destroy(item->widget);
+       panel_window_list_schedule_redraw(item->panel);
+       free(item);
+}
+
+static int
+panel_list_item_exists(struct panel *panel, struct surface *surface)
+{
+       struct list_item *p_item, *s_item;
+
+       wl_list_for_each(p_item, &panel->window_list, link) {
+               wl_list_for_each(s_item, &surface->item_list, surface_link) {
+                       if (p_item == s_item)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void
+output_update_window_list(struct output *output, struct surface *surface)
+{
+       struct list_item *item, *next;
+       struct panel *panel;
+
+       panel = output->panel;
+
+       /* Make a list item for each panel of the surfaces output mask */
+       if ((1 << output->id) & surface->output_mask) {
+               if (!panel_list_item_exists(panel, surface)) {
+                       /* TODO: Use a real icon instead of
+                        * passing NULL for the fallback */
+                       item = panel_list_item_add(panel, NULL, surface->title);
+                       wl_list_insert(surface->item_list.prev,
+                                                       &item->surface_link);
+                       item->surface = surface;
+               }
+       } else {
+               /* Remove item from panel if surface
+                * is no longer on the output */
+               wl_list_for_each_safe(item, next, &surface->item_list,
+                                                               surface_link) {
+                       if (item->panel == panel)
+                               panel_list_item_remove(item);
+               }
+       }
+
+       panel_window_list_schedule_redraw(panel);
+}
+
+static struct surface*
+surface_data_create_surface(struct surface_data *surface_data)
+{
+       struct surface *surface;
+
+       surface = calloc(1, sizeof *surface);
+
+       if (!surface) {
+               fprintf(stderr, "ERROR: Failed to allocate memory!\n");
+               exit(EXIT_FAILURE);
+       }
+
+       surface->surface_data = surface_data;
+       surface->title = strdup("unknown");
+       surface->output_mask = 1;
+       wl_list_init(&surface->item_list);
+
+       return surface;
+}
+
+static void
+surface_data_destroy_surface(struct surface *surface)
+{
+       struct list_item *item, *next;
+
+       wl_list_for_each_safe(item, next, &surface->item_list, surface_link)
+               panel_list_item_remove(item);
+
+       free(surface->title);
+       free(surface);
+}
+
+static struct surface *
+surface_data_get_surface(struct desktop *desktop, struct surface_data 
*surface_data)
+{
+       struct output *output;
+       struct list_item *item;
+
+       wl_list_for_each(output, &desktop->outputs, link) {
+               wl_list_for_each(item, &output->panel->window_list, link) {
+                       if (surface_data == item->surface->surface_data)
+                               return item->surface;
+               }
+       }
+
+       return NULL;
+}
+
+static void
+update_list_items(struct desktop *desktop, struct surface *surface)
+{
+       struct output *output;
+
+       wl_list_for_each(output, &desktop->outputs, link)
+               output_update_window_list(output, surface);
+}
+
+static void
+surface_data_set_output_mask(void *data,
+                               struct surface_data *surface_data,
+                               uint32_t output_mask)
+{
+       struct desktop *desktop;
+       struct surface *surface;
+
+       desktop = data;
+
+       surface = surface_data_get_surface(desktop, surface_data);
+
+       if (!surface)
+               surface = surface_data_create_surface(surface_data);
+
+       surface->output_mask = output_mask;
+
+       update_list_items(desktop, surface);
+}
+
+static void
+surface_data_set_title(void *data,
+                               struct surface_data *surface_data,
+                               const char *title)
+{
+       struct desktop *desktop;
+       struct surface *surface;
+
+       desktop = data;
+
+       surface = surface_data_get_surface(desktop, surface_data);
+
+       if (!surface)
+               surface = surface_data_create_surface(surface_data);
+
+       if (surface->title)
+               free(surface->title);
+       surface->title = strdup(title);
+
+       update_list_items(desktop, surface);
+}
+
+static void
+surface_data_destroy_handler(void *data, struct surface_data *surface_data)
+{
+       struct list_item *item, *next;
+       struct desktop *desktop;
+       struct output *output;
+       struct panel *panel;
+
+       desktop = data;
+
+       surface_data_destroy(surface_data);
+
+       wl_list_for_each(output, &desktop->outputs, link) {
+               panel = output->panel;
+               wl_list_for_each_safe(item, next, &panel->window_list, link) {
+                       if (surface_data == item->surface->surface_data) {
+                               surface_data_destroy_surface(item->surface);
+                               return;
+                       }
+               }
+       }
+}
+
+static const struct surface_data_listener surface_data_listener = {
+       surface_data_set_output_mask,
+       surface_data_set_title,
+       surface_data_destroy_handler
+};
+
+static void
+surface_data_receive_surface_object(void *data,
+                               struct surface_data_manager *manager,
+                               struct surface_data *surface_data)
+{
+       surface_data_add_listener(surface_data,
+                                  &surface_data_listener, data);
+}
+
+static const struct surface_data_manager_listener 
surface_data_manager_listener = {
+       surface_data_receive_surface_object
+};
+
 static struct background *
 background_create(struct desktop *desktop)
 {
@@ -941,10 +1399,12 @@ create_output(struct desktop *desktop, uint32_t id)
        if (!output)
                return;
 
+       output->id = desktop->output_count++;
+
        output->output = wl_display_bind(display_get_display(desktop->display),
                                         id, &wl_output_interface);
 
-       wl_list_insert(&desktop->outputs, &output->link);
+       wl_list_insert(desktop->outputs.prev, &output->link);
 }
 
 static void
@@ -957,6 +1417,12 @@ 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, "surface_data_manager") == 0) {
+               desktop->surface_data_manager =
+                       wl_display_bind(display, id,
+                                       &surface_data_manager_interface);
+               surface_data_manager_add_listener(desktop->surface_data_manager,
+                                       &surface_data_manager_listener, 
desktop);
        } else if (!strcmp(interface, "wl_output")) {
                create_output(desktop, id);
        }
@@ -1011,6 +1477,8 @@ int main(int argc, char *argv[])
                return -1;
        }
 
+       desktop.output_count = 0;
+
        display_set_user_data(desktop.display, &desktop);
        wl_display_add_global_listener(display_get_display(desktop.display),
                                       global_handler, &desktop);
diff --git a/src/compositor.c b/src/compositor.c
index 417c508..bcaaf2d 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -368,6 +368,8 @@ weston_surface_update_output_mask(struct weston_surface 
*es, uint32_t mask)
                if (1 << output->id & left)
                        wl_surface_send_leave(&es->surface.resource, resource);
        }
+
+       es->compositor->shell_interface.send_output_mask(es);
 }
 
 static void
diff --git a/src/compositor.h b/src/compositor.h
index aea4f8d..ec5e5a5 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -89,6 +89,7 @@ struct weston_shell_interface {
        int (*move)(struct shell_surface *shsurf, struct weston_seat *ws);
        int (*resize)(struct shell_surface *shsurf,
                      struct weston_seat *ws, uint32_t edges);
+       void (*send_output_mask)(struct weston_surface *surface);
 
 };
 
diff --git a/src/shell.c b/src/shell.c
index e2715d6..f9fcae3 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -97,6 +97,8 @@ struct desktop_shell {
                uint32_t deathstamp;
        } child;
 
+       struct wl_resource *surface_data_manager;
+
        bool locked;
        bool showing_input_panels;
        bool prepare_event_sent;
@@ -152,6 +154,11 @@ struct ping_timer {
        uint32_t serial;
 };
 
+struct surface_data {
+       struct shell_surface *shsurf;
+       struct wl_resource resource;
+};
+
 struct shell_surface {
        struct wl_resource resource;
 
@@ -202,6 +209,7 @@ struct shell_surface {
        struct wl_list link;
 
        const struct weston_shell_client *client;
+       struct surface_data *surface_data;
 };
 
 struct shell_grab {
@@ -1392,6 +1400,123 @@ shell_surface_pong(struct wl_client *client, struct 
wl_resource *resource,
 }
 
 static void
+surface_data_object_destroy(struct wl_resource *resource)
+{
+       struct shell_surface *shsurf;
+       struct surface_data *surface_data = resource->data;
+
+       shsurf = surface_data->shsurf;
+
+       free(surface_data);
+
+       if (!shsurf)
+               return;
+
+       shsurf->surface_data = NULL;
+}
+
+static void
+surface_data_destroy_handler(struct wl_client *client,
+                                       struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct surface_data_interface
+                                       surface_data_implementation = {
+       surface_data_destroy_handler
+};
+
+static int
+create_surface_data(struct desktop_shell *shell, struct shell_surface *shsurf)
+{
+       struct surface_data *surface_data;
+
+       surface_data = malloc(sizeof *surface_data);
+       if (surface_data == NULL)
+               return -1;
+
+       surface_data->resource.data = surface_data;
+       surface_data->resource.object.id = 0;
+       surface_data->resource.object.interface = &surface_data_interface;
+       surface_data->resource.destroy = surface_data_object_destroy;
+       surface_data->resource.object.implementation =
+                       (void (**)(void)) &surface_data_implementation;
+       surface_data->shsurf = shsurf;
+       wl_signal_init(&surface_data->resource.destroy_signal);
+
+       wl_client_add_resource(shell->surface_data_manager->client,
+                                       &surface_data->resource);
+
+       shsurf->surface_data = surface_data;
+
+       return 0;
+}
+
+static void
+send_surface_data_object(struct desktop_shell *shell, struct shell_surface 
*shsurf)
+{
+       surface_data_manager_send_surface_object(shell->surface_data_manager,
+                                       &shsurf->surface_data->resource);
+}
+
+static bool
+surface_is_window_list_candidate(struct weston_surface *surface,
+                                       struct shell_surface *out)
+{
+       struct desktop_shell *shell;
+       struct shell_surface *shsurf;
+
+       shsurf = get_shell_surface(surface);
+       if (!shsurf)
+               return false;
+
+       shell = shsurf->shell;
+
+       if (!shell->surface_data_manager)
+               return false;
+
+       switch (shsurf->type) {
+       default:
+       case SHELL_SURFACE_TRANSIENT:
+       case SHELL_SURFACE_POPUP:
+       case SHELL_SURFACE_NONE:
+               return false;
+       case SHELL_SURFACE_FULLSCREEN:
+       case SHELL_SURFACE_MAXIMIZED:
+       case SHELL_SURFACE_TOPLEVEL:
+               if (!shsurf->surface_data) {
+                       if (create_surface_data(shell, shsurf))
+                               return 0;
+                       send_surface_data_object(shell, shsurf);
+               }
+               *out = *shsurf;
+               return true;
+       }
+}
+
+static void
+send_surface_data_output_mask(struct weston_surface *surface)
+{
+       struct shell_surface shsurf;
+
+       if (surface_is_window_list_candidate(surface, &shsurf))
+               surface_data_send_output_mask(&shsurf.surface_data->resource,
+                                               surface->output_mask);
+}
+
+static void
+send_surface_data_title(struct weston_surface *surface)
+{
+       struct shell_surface shsurf;
+
+       if (surface_is_window_list_candidate(surface, &shsurf))
+               surface_data_send_title(&shsurf.surface_data->resource,
+                                               shsurf.title == NULL ?
+                                               "Surface" : shsurf.title);
+}
+
+static void
 shell_surface_set_title(struct wl_client *client,
                        struct wl_resource *resource, const char *title)
 {
@@ -1399,6 +1524,7 @@ shell_surface_set_title(struct wl_client *client,
 
        free(shsurf->title);
        shsurf->title = strdup(title);
+       send_surface_data_title(shsurf->surface);
 }
 
 static void
@@ -1510,6 +1636,8 @@ set_surface_type(struct shell_surface *shsurf)
        default:
                break;
        }
+
+       send_surface_data_title(surface);
 }
 
 static void
@@ -1907,6 +2035,10 @@ static const struct wl_shell_surface_interface 
shell_surface_implementation = {
 static void
 destroy_shell_surface(struct shell_surface *shsurf)
 {
+       if (shsurf->surface_data) {
+               shsurf->surface_data->shsurf = NULL;
+               surface_data_send_gone(&shsurf->surface_data->resource);
+       }
        if (shsurf->popup.grab.pointer)
                wl_pointer_end_grab(shsurf->popup.grab.pointer);
 
@@ -2291,6 +2423,20 @@ static const struct desktop_shell_interface 
desktop_shell_implementation = {
        desktop_shell_set_grab_surface
 };
 
+static void
+surface_data_send_all_info(struct desktop_shell *shell)
+{
+       struct weston_surface *surface;
+       struct workspace *ws;
+
+       ws = get_current_workspace(shell);
+
+       wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+               send_surface_data_output_mask(surface);
+               send_surface_data_title(surface);
+       }
+}
+
 static enum shell_surface_type
 get_shell_surface_type(struct weston_surface *surface)
 {
@@ -3118,6 +3264,37 @@ bind_desktop_shell(struct wl_client *client,
 }
 
 static void
+unbind_surface_data_manager(struct wl_resource *resource)
+{
+       struct desktop_shell *shell = resource->data;
+
+       shell->surface_data_manager = NULL;
+       free(resource);
+}
+
+static void
+bind_surface_data_manager(struct wl_client *client,
+                  void *data, uint32_t version, uint32_t id)
+{
+       struct desktop_shell *shell = data;
+       struct wl_resource *resource;
+
+       resource = wl_client_add_object(client, &surface_data_manager_interface,
+                                       NULL, id, shell);
+
+       if (client == shell->child.client) {
+               resource->destroy = unbind_surface_data_manager;
+               shell->surface_data_manager = resource;
+               surface_data_send_all_info(shell);
+               return;
+       }
+
+       wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "permission to bind desktop_shell denied");
+       wl_resource_destroy(resource);
+}
+
+static void
 screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
 {
        struct desktop_shell *shell = surface->private;
@@ -3723,6 +3900,7 @@ module_init(struct weston_compositor *ec)
        ec->shell_interface.set_transient = set_transient;
        ec->shell_interface.move = surface_move;
        ec->shell_interface.resize = surface_resize;
+       ec->shell_interface.send_output_mask = send_surface_data_output_mask;
 
        wl_list_init(&shell->screensaver.surfaces);
        wl_list_init(&shell->input_panel.surfaces);
@@ -3774,6 +3952,10 @@ module_init(struct weston_compositor *ec)
                                  shell, bind_workspace_manager) == NULL)
                return -1;
 
+       if (wl_display_add_global(ec->wl_display, 
&surface_data_manager_interface,
+                                 shell, bind_surface_data_manager) == NULL)
+               return -1;
+
        shell->child.deathstamp = weston_compositor_get_time();
        if (launch_desktop_shell_process(shell) != 0)
                return -1;
-- 
1.7.11.4

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

Reply via email to