summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clients/window.c149
-rw-r--r--clients/window.h9
2 files changed, 155 insertions, 3 deletions
diff --git a/clients/window.c b/clients/window.c
index 695cf5d..30bb71e 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -85,6 +85,7 @@ struct display {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
+ struct wl_subcompositor *subcompositor;
struct wl_shell *shell;
struct wl_shm *shm;
struct wl_data_device_manager *data_device_manager;
@@ -189,6 +190,9 @@ struct surface {
struct window *window;
struct wl_surface *surface;
+ struct wl_subsurface *subsurface;
+ int synchronized;
+ int synchronized_default;
struct toysurface *toysurface;
struct widget *widget;
@@ -202,6 +206,8 @@ struct surface {
enum wl_output_transform buffer_transform;
cairo_surface_t *cairo_surface;
+
+ struct wl_list link;
};
struct window {
@@ -240,6 +246,9 @@ struct window {
struct frame *frame;
+ /* struct surface::link, contains also main_surface */
+ struct wl_list subsurface_list;
+
void *user_data;
struct wl_list link;
};
@@ -1197,12 +1206,21 @@ window_has_focus(struct window *window)
static void
window_flush(struct window *window)
{
+ struct surface *surface;
+
if (window->type == TYPE_NONE) {
window->type = TYPE_TOPLEVEL;
if (window->shell_surface)
wl_shell_surface_set_toplevel(window->shell_surface);
}
+ wl_list_for_each(surface, &window->subsurface_list, link) {
+ if (surface == window->main_surface)
+ continue;
+
+ surface_flush(surface);
+ }
+
surface_flush(window->main_surface);
}
@@ -1299,11 +1317,15 @@ surface_destroy(struct surface *surface)
if (surface->opaque_region)
wl_region_destroy(surface->opaque_region);
+ if (surface->subsurface)
+ wl_subsurface_destroy(surface->subsurface);
+
wl_surface_destroy(surface->surface);
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);
+ wl_list_remove(&surface->link);
free(surface);
}
@@ -1373,7 +1395,16 @@ widget_find_widget(struct widget *widget, int32_t x, int32_t y)
static struct widget *
window_find_widget(struct window *window, int32_t x, int32_t y)
{
- return widget_find_widget(window->main_surface->widget, x, y);
+ struct surface *surface;
+ struct widget *widget;
+
+ wl_list_for_each(surface, &window->subsurface_list, link) {
+ widget = widget_find_widget(surface->widget, x, y);
+ if (widget)
+ return widget;
+ }
+
+ return NULL;
}
static struct widget *
@@ -1423,8 +1454,13 @@ void
widget_destroy(struct widget *widget)
{
struct display *display = widget->window->display;
+ struct surface *surface = widget->surface;
struct input *input;
+ /* Destroy the sub-surface along with the root widget */
+ if (surface->widget == widget && surface->subsurface)
+ surface_destroy(widget->surface);
+
if (widget->tooltip) {
free(widget->tooltip);
widget->tooltip = NULL;
@@ -1498,12 +1534,15 @@ widget_get_cairo_surface(struct widget *widget)
cairo_t *
widget_cairo_create(struct widget *widget)
{
+ struct surface *surface = widget->surface;
cairo_surface_t *cairo_surface;
cairo_t *cr;
cairo_surface = widget_get_cairo_surface(widget);
cr = cairo_create(cairo_surface);
+ cairo_translate(cr, -surface->allocation.x, -surface->allocation.y);
+
return cr;
}
@@ -3220,6 +3259,36 @@ window_move(struct window *window, struct input *input, uint32_t serial)
}
static void
+surface_set_synchronized(struct surface *surface)
+{
+ if (!surface->subsurface)
+ return;
+
+ if (surface->synchronized)
+ return;
+
+ wl_subsurface_set_sync(surface->subsurface);
+ surface->synchronized = 1;
+}
+
+static void
+surface_set_synchronized_default(struct surface *surface)
+{
+ if (!surface->subsurface)
+ return;
+
+ if (surface->synchronized == surface->synchronized_default)
+ return;
+
+ if (surface->synchronized_default)
+ wl_subsurface_set_sync(surface->subsurface);
+ else
+ wl_subsurface_set_desync(surface->subsurface);
+
+ surface->synchronized = surface->synchronized_default;
+}
+
+static void
surface_resize(struct surface *surface)
{
struct widget *widget = surface->widget;
@@ -3241,11 +3310,18 @@ surface_resize(struct surface *surface)
widget->allocation.height,
widget->user_data);
+ if (surface->subsurface &&
+ (surface->allocation.x != widget->allocation.x ||
+ surface->allocation.y != widget->allocation.y)) {
+ wl_subsurface_set_position(surface->subsurface,
+ widget->allocation.x,
+ widget->allocation.y);
+ }
if (surface->allocation.width != widget->allocation.width ||
surface->allocation.height != widget->allocation.height) {
- surface->allocation = widget->allocation;
window_schedule_redraw(widget->window);
}
+ surface->allocation = widget->allocation;
if (widget->opaque)
wl_region_add(surface->opaque_region, 0, 0,
@@ -3256,6 +3332,8 @@ surface_resize(struct surface *surface)
static void
idle_resize(struct window *window)
{
+ struct surface *surface;
+
window->resize_needed = 0;
widget_set_allocation(window->main_surface->widget,
@@ -3265,6 +3343,19 @@ idle_resize(struct window *window)
window->pending_allocation.height);
surface_resize(window->main_surface);
+
+ /* The main surface is in the list, too. Main surface's
+ * resize_handler is responsible for calling widget_set_allocation()
+ * on all sub-surface root widgets, so they will be resized
+ * properly.
+ */
+ wl_list_for_each(surface, &window->subsurface_list, link) {
+ if (surface == window->main_surface)
+ continue;
+
+ surface_set_synchronized(surface);
+ surface_resize(surface);
+ }
}
void
@@ -3377,17 +3468,23 @@ static void
idle_redraw(struct task *task, uint32_t events)
{
struct window *window = container_of(task, struct window, redraw_task);
+ struct surface *surface;
if (window->resize_needed)
idle_resize(window);
- widget_redraw(window->main_surface->widget);
+ wl_list_for_each(surface, &window->subsurface_list, link)
+ widget_redraw(surface->widget);
+
window->redraw_needed = 0;
wl_list_init(&window->redraw_task.link);
window->frame_cb = wl_surface_frame(window->main_surface->surface);
wl_callback_add_listener(window->frame_cb, &listener, window);
window_flush(window);
+
+ wl_list_for_each(surface, &window->subsurface_list, link)
+ surface_set_synchronized_default(surface);
}
void
@@ -3687,6 +3784,8 @@ surface_create(struct window *window)
surface->surface = wl_compositor_create_surface(display->compositor);
wl_surface_add_listener(surface->surface, &surface_listener, window);
+ wl_list_insert(&window->subsurface_list, &surface->link);
+
return surface;
}
@@ -3702,6 +3801,7 @@ window_create_internal(struct display *display,
return NULL;
memset(window, 0, sizeof *window);
+ wl_list_init(&window->subsurface_list);
window->display = display;
window->parent = parent;
@@ -3952,6 +4052,42 @@ window_set_buffer_type(struct window *window, enum window_buffer_type type)
window->main_surface->buffer_type = type;
}
+struct widget *
+window_add_subsurface(struct window *window, void *data,
+ enum subsurface_mode default_mode)
+{
+ struct widget *widget;
+ struct surface *surface;
+ struct wl_surface *parent;
+ struct wl_subcompositor *subcompo = window->display->subcompositor;
+
+ if (!subcompo)
+ return NULL;
+
+ surface = surface_create(window);
+ widget = widget_create(window, surface, data);
+ wl_list_init(&widget->link);
+ surface->widget = widget;
+
+ parent = window->main_surface->surface;
+ surface->subsurface = wl_subcompositor_get_subsurface(subcompo,
+ surface->surface,
+ parent);
+ surface->synchronized = 1;
+
+ switch (default_mode) {
+ case SUBSURFACE_SYNCHRONIZED:
+ surface->synchronized_default = 1;
+ break;
+ case SUBSURFACE_DESYNCHRONIZED:
+ surface->synchronized_default = 0;
+ break;
+ default:
+ assert(!"bad enum subsurface_mode");
+ }
+
+ return widget;
+}
static void
display_handle_geometry(void *data,
@@ -4223,6 +4359,10 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
&text_cursor_position_interface, 1);
} else if (strcmp(interface, "workspace_manager") == 0) {
init_workspace_manager(d, id);
+ } else if (strcmp(interface, "wl_subcompositor") == 0) {
+ d->subcompositor =
+ wl_registry_bind(registry, id,
+ &wl_subcompositor_interface, 1);
}
if (d->global_handler)
@@ -4516,6 +4656,9 @@ display_destroy(struct display *display)
fini_egl(display);
#endif
+ if (display->subcompositor)
+ wl_subcompositor_destroy(display->subcompositor);
+
if (display->shell)
wl_shell_destroy(display->shell);
diff --git a/clients/window.h b/clients/window.h
index 815b3f1..2f93bd4 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -259,6 +259,15 @@ window_destroy(struct window *window);
struct widget *
window_add_widget(struct window *window, void *data);
+enum subsurface_mode {
+ SUBSURFACE_SYNCHRONIZED,
+ SUBSURFACE_DESYNCHRONIZED
+};
+
+struct widget *
+window_add_subsurface(struct window *window, void *data,
+ enum subsurface_mode default_mode);
+
typedef void (*data_func_t)(void *data, size_t len,
int32_t x, int32_t y, void *user_data);