commit 300de285384cdf277c25941854807c449d416375
parent 0dc0ed350e20a22189a4f31e7dba2ee5dd52167c
Author: Michael Forney <mforney@mforney.org>
Date: Thu, 16 Jan 2014 18:06:26 -0800
Move common state to swc_view
Diffstat:
10 files changed, 374 insertions(+), 329 deletions(-)
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -23,6 +23,7 @@
struct view
{
struct swc_view base;
+ struct wl_listener event_listener;
struct swc_compositor * compositor;
struct swc_surface * surface;
@@ -40,9 +41,7 @@ struct view
bool damaged;
} border;
- bool mapped;
-
- struct wl_listener surface_event_listener;
+ struct wl_list link;
};
/* Rendering {{{ */
@@ -51,50 +50,39 @@ struct render_target
{
struct wld_buffer * buffer;
struct swc_rectangle geometry;
+ uint32_t mask;
};
-static void repaint_surface(struct render_target * target,
- struct swc_surface * surface,
- pixman_region32_t * damage)
+static void repaint_view(struct render_target * target, struct view * view,
+ pixman_region32_t * damage)
{
- pixman_region32_t surface_damage;
- pixman_region32_t border_damage;
- pixman_region32_t surface_region;
- struct view * view = (void *) surface->view;
+ pixman_region32_t view_region, view_damage, border_damage;
+ const struct swc_rectangle * geometry = &view->base.geometry;
- if (!surface->state.buffer)
+ if (!view->base.buffer)
return;
- pixman_region32_init_with_extents(&surface_damage, &view->extents);
+ pixman_region32_init_rect(&view_region, geometry->x, geometry->y,
+ geometry->width, geometry->height);
+ pixman_region32_init_with_extents(&view_damage, &view->extents);
pixman_region32_init(&border_damage);
- pixman_region32_init_rect
- (&surface_region, surface->geometry.x, surface->geometry.y,
- surface->geometry.width, surface->geometry.height);
- pixman_region32_intersect(&surface_damage, &surface_damage, damage);
- pixman_region32_subtract(&surface_damage, &surface_damage, &view->clip);
- pixman_region32_subtract(&border_damage, &surface_damage, &surface_region);
- pixman_region32_intersect(&surface_damage, &surface_damage,
- &surface_region);
+ pixman_region32_intersect(&view_damage, &view_damage, damage);
+ pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
+ pixman_region32_subtract(&border_damage, &view_damage, &view_region);
+ pixman_region32_intersect(&view_damage, &view_damage, &view_region);
- pixman_region32_fini(&surface_region);
+ pixman_region32_fini(&view_region);
- if (pixman_region32_not_empty(&surface_damage))
+ if (pixman_region32_not_empty(&view_damage))
{
- DEBUG("\tDRM surface %u { x: %d, y: %d, w: %u, h: %u }\n",
- wl_resource_get_id(surface->resource),
- surface->geometry.x, surface->geometry.y,
- surface->geometry.width, surface->geometry.height);
-
- pixman_region32_translate(&surface_damage,
- -surface->geometry.x, -surface->geometry.y);
- wld_copy_region(swc.drm->renderer, surface->state.buffer->wld,
- surface->geometry.x - target->geometry.x,
- surface->geometry.y - target->geometry.y,
- &surface_damage);
+ pixman_region32_translate(&view_damage, -geometry->x, -geometry->y);
+ wld_copy_region(swc.drm->renderer, view->base.buffer->wld,
+ geometry->x - target->geometry.x,
+ geometry->y - target->geometry.y, &view_damage);
}
- pixman_region32_fini(&surface_damage);
+ pixman_region32_fini(&view_damage);
/* Draw border */
if (pixman_region32_not_empty(&border_damage))
@@ -112,9 +100,9 @@ static void repaint_surface(struct render_target * target,
static void renderer_repaint(struct render_target * target,
pixman_region32_t * damage,
pixman_region32_t * base_damage,
- struct wl_list * surfaces)
+ struct wl_list * views)
{
- struct swc_surface * surface;
+ struct view * view;
DEBUG("Rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
target->geometry.x, target->geometry.y,
@@ -128,20 +116,21 @@ static void renderer_repaint(struct render_target * target,
wld_fill_region(swc.drm->renderer, 0xff000000, base_damage);
}
- wl_list_for_each_reverse(surface, surfaces, link)
+ wl_list_for_each_reverse(view, views, link)
{
- if (swc_rectangle_overlap(&target->geometry, &surface->geometry))
- repaint_surface(target, surface, damage);
+ if (view->base.screens & target->mask)
+ repaint_view(target, view, damage);
}
wld_flush(swc.drm->renderer);
}
-static void renderer_attach(struct view * view, struct swc_buffer * buffer)
+static bool renderer_attach(struct view * view, struct swc_buffer * buffer)
{
+ return true;
}
-static void renderer_flush_surface(struct swc_surface * surface)
+static void renderer_flush_view(struct view * view)
{
}
@@ -150,12 +139,11 @@ static void renderer_flush_surface(struct swc_surface * surface)
/* Surface Views {{{ */
/**
- * Adds damage from the region below a surface, taking into account it's clip
+ * Adds damage from the region below a view, taking into account it's clip
* region, to the region specified by `damage'.
*/
-static void damage_below_surface(struct swc_surface * surface)
+static void damage_below_view(struct view * view)
{
- struct view * view = (void *) surface->view;
struct swc_compositor * compositor = view->compositor;
pixman_region32_t damage_below;
@@ -169,101 +157,40 @@ static void damage_below_surface(struct swc_surface * surface)
/**
* Completely damages the surface and its border.
*/
-static void damage_surface(struct swc_surface * surface)
+static void damage_view(struct view * view)
{
- struct view * view = (void *) surface->view;
- printf("damaging surface\n");
-
- pixman_region32_fini(&surface->state.damage);
- pixman_region32_init_rect(&surface->state.damage, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ damage_below_view(view);
view->border.damaged = true;
}
-static void update_extents(struct swc_surface * surface)
+static void update_extents(struct view * view)
{
- struct view * view = (void *) surface->view;
-
- view->extents.x1 = surface->geometry.x - view->border.width;
- view->extents.y1 = surface->geometry.y - view->border.width;
- view->extents.x2 = surface->geometry.x + surface->geometry.width
+ view->extents.x1 = view->base.geometry.x - view->border.width;
+ view->extents.y1 = view->base.geometry.y - view->border.width;
+ view->extents.x2 = view->base.geometry.x + view->base.geometry.width
+ view->border.width;
- view->extents.y2 = surface->geometry.y + surface->geometry.height
+ view->extents.y2 = view->base.geometry.y + view->base.geometry.height
+ view->border.width;
/* Damage border. */
view->border.damaged = true;
}
-static void update_screens(struct swc_surface * surface)
+static bool update(struct swc_view * base)
{
- struct view * view = (void *) surface->view;
- uint32_t old_screens = surface->screens, new_screens = 0,
- entered_screens, left_screens, changed_screens;
+ struct view * view = (void *) base;
struct swc_screen_internal * screen;
- struct swc_output * output;
- struct wl_client * client;
- struct wl_resource * resource;
- if (view->mapped)
- {
- wl_list_for_each(screen, &swc.screens, link)
- {
- if (swc_rectangle_overlap(&screen->base.geometry, &surface->geometry))
- new_screens |= swc_screen_mask(screen);
- }
- }
-
- if (new_screens == old_screens)
- return;
-
- entered_screens = new_screens & ~old_screens;
- left_screens = old_screens & ~new_screens;
- changed_screens = old_screens ^ new_screens;
+ if (!view->base.visible)
+ return false;
wl_list_for_each(screen, &swc.screens, link)
{
- if (!(changed_screens & swc_screen_mask(screen)))
- continue;
-
- output = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
- client = wl_resource_get_client(surface->resource);
- resource = wl_resource_find_for_client(&output->resources, client);
-
- if (resource)
- {
- if (entered_screens & swc_screen_mask(screen))
- wl_surface_send_enter(surface->resource, resource);
- else if (left_screens & swc_screen_mask(screen))
- wl_surface_send_leave(surface->resource, resource);
- }
+ if (view->base.screens & swc_screen_mask(screen))
+ swc_compositor_schedule_update(view->compositor, screen);
}
- surface->screens = new_screens;
-}
-
-static void update(struct swc_view * view);
-
-static void handle_surface_event(struct wl_listener * listener, void * data)
-{
- struct view * view
- = CONTAINER_OF(listener, typeof(*view), surface_event_listener);
- struct swc_event * event = data;
- struct swc_surface_event_data * event_data = event->data;
- struct swc_surface * surface = event_data->surface;
-
- switch (event->type)
- {
- case SWC_SURFACE_EVENT_TYPE_RESIZE:
- damage_below_surface(surface);
-
- update_extents(surface);
- update(&view->base);
- update_screens(surface);
-
- break;
- }
+ return true;
}
static void remove_(struct swc_view * base)
@@ -271,69 +198,84 @@ static void remove_(struct swc_view * base)
struct view * view = (void *) base;
swc_compositor_surface_hide(view->surface);
- wl_list_remove(&view->surface_event_listener.link);
pixman_region32_fini(&view->clip);
free(view);
}
-static void attach(struct swc_view * base, struct swc_buffer * buffer)
+static bool attach(struct swc_view * base, struct swc_buffer * buffer)
{
struct view * view = (void *) base;
- renderer_attach(view, buffer);
+ if (!renderer_attach(view, buffer))
+ return false;
+
+ return true;
}
-static void update(struct swc_view * base)
+static bool move(struct swc_view * base, int32_t x, int32_t y)
{
struct view * view = (void *) base;
- struct swc_screen_internal * screen;
-
- if (!view->mapped)
- return;
- wl_list_for_each(screen, &swc.screens, link)
+ if (view->base.visible)
{
- if (view->surface->screens & swc_screen_mask(screen))
- swc_compositor_schedule_update(view->compositor, screen);
+ damage_below_view(view);
+ update(&view->base);
}
+
+ return true;
}
-static void move(struct swc_view * base, int32_t x, int32_t y)
+static void resize(struct swc_view * base)
{
struct view * view = (void *) base;
- struct swc_surface * surface = view->surface;
-
- if (x == surface->geometry.x && y == surface->geometry.y)
- return;
-
- if (view->mapped)
- damage_below_surface(surface);
- surface->geometry.x = x;
- surface->geometry.y = y;
-
- update_extents(surface);
-
- if (view->mapped)
+ if (view->base.visible)
{
- /* Assume worst-case no clipping until we draw the next frame (in case
- * the surface gets moved again before that). */
- pixman_region32_init(&view->clip);
-
- damage_below_surface(surface);
- update(&view->base);
- update_screens(surface);
+ damage_below_view(view);
update(&view->base);
}
}
-const struct swc_view_impl view_impl = {
- .remove = &remove_,
- .attach = &attach,
+const static struct swc_view_impl view_impl = {
.update = &update,
- .move = &move
+ .attach = &attach,
+ .move = &move,
+ .resize = &resize,
+ .remove = &remove_,
};
+static void handle_view_event(struct wl_listener * listener, void * data)
+{
+ struct view * view = CONTAINER_OF(listener, typeof(*view), event_listener);
+ struct swc_event * event = data;
+
+ switch (event->type)
+ {
+ case SWC_VIEW_EVENT_MOVED:
+ update_extents(view);
+
+ if (view->base.visible)
+ {
+ /* Assume worst-case no clipping until we draw the next frame (in case
+ * the surface gets moved again before that). */
+ pixman_region32_init(&view->clip);
+
+ damage_below_view(view);
+ update(&view->base);
+ }
+ break;
+ case SWC_VIEW_EVENT_RESIZED:
+ update_extents(view);
+
+ if (view->base.visible)
+ {
+ damage_below_view(view);
+ update(&view->base);
+ }
+ break;
+ }
+}
+
bool swc_compositor_add_surface(struct swc_compositor * compositor,
struct swc_surface * surface)
{
@@ -345,18 +287,18 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor,
return false;
swc_view_initialize(&view->base, &view_impl);
+ view->base.visible = false;
+ view->event_listener.notify = &handle_view_event;
+ wl_signal_add(&view->base.event_signal, &view->event_listener);
view->compositor = compositor;
view->surface = surface;
- view->mapped = false;
- view->extents.x1 = surface->geometry.x;
- view->extents.y1 = surface->geometry.y;
- view->extents.x2 = surface->geometry.x + surface->geometry.width;
- view->extents.y2 = surface->geometry.y + surface->geometry.height;
+ view->extents.x1 = 0;
+ view->extents.y1 = 0;
+ view->extents.x2 = 0;
+ view->extents.y2 = 0;
view->border.width = 0;
view->border.color = 0x000000;
view->border.damaged = false;
- view->surface_event_listener.notify = &handle_surface_event;
- wl_signal_add(&surface->event_signal, &view->surface_event_listener);
pixman_region32_init(&view->clip);
swc_surface_set_view(surface, &view->base);
@@ -366,26 +308,23 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor,
void swc_compositor_surface_show(struct swc_surface * surface)
{
struct view * view = (void *) surface->view;
- struct swc_compositor * compositor = view->compositor;
if (view->base.impl != &view_impl)
return;
- if (view->mapped)
+ if (view->base.visible)
return;
printf("showing surface %u\n", wl_resource_get_id(surface->resource));
- view->mapped = true;
-
/* Assume worst-case no clipping until we draw the next frame (in case the
* surface gets moved before that. */
pixman_region32_clear(&view->clip);
- damage_surface(surface);
- update_screens(surface);
+ damage_view(view);
+ swc_view_set_visibility(&view->base, true);
update(&view->base);
- wl_list_insert(&compositor->surfaces, &surface->link);
+ wl_list_insert(&view->compositor->views, &view->link);
}
void swc_compositor_surface_hide(struct swc_surface * surface)
@@ -395,17 +334,15 @@ void swc_compositor_surface_hide(struct swc_surface * surface)
if (view->base.impl != &view_impl)
return;
- if (!view->mapped)
+ if (!view->base.visible)
return;
/* Update all the outputs the surface was on. */
update(&view->base);
- view->mapped = false;
-
- damage_below_surface(surface);
- update_screens(surface);
- wl_list_remove(&surface->link);
+ damage_below_view(view);
+ swc_view_set_visibility(&view->base, false);
+ wl_list_remove(&view->link);
}
void swc_compositor_surface_set_border_width(struct swc_surface * surface,
@@ -421,7 +358,7 @@ void swc_compositor_surface_set_border_width(struct swc_surface * surface,
/* XXX: Damage above surface for transparent surfaces? */
- update_extents(surface);
+ update_extents(view);
update(&view->base);
}
@@ -445,63 +382,61 @@ void swc_compositor_surface_set_border_color(struct swc_surface * surface,
static void calculate_damage(struct swc_compositor * compositor)
{
- struct swc_surface * surface;
struct view * view;
- pixman_region32_t surface_opaque;
+ pixman_region32_t surface_opaque, * surface_damage;
pixman_region32_clear(&compositor->opaque);
pixman_region32_init(&surface_opaque);
- /* Go through surfaces top-down to calculate clipping regions. */
- wl_list_for_each(surface, &compositor->surfaces, link)
+ /* Go through views top-down to calculate clipping regions. */
+ wl_list_for_each(view, &compositor->views, link)
{
- view = (void *) surface->view;
-
/* Clip the surface by the opaque region covering it. */
pixman_region32_copy(&view->clip, &compositor->opaque);
/* Translate the opaque region to global coordinates. */
- pixman_region32_copy(&surface_opaque, &surface->state.opaque);
- pixman_region32_translate(&surface_opaque, surface->geometry.x,
- surface->geometry.y);
+ pixman_region32_copy(&surface_opaque, &view->surface->state.opaque);
+ pixman_region32_translate(&surface_opaque,
+ view->base.geometry.x, view->base.geometry.y);
/* Add the surface's opaque region to the accumulated opaque
* region. */
pixman_region32_union(&compositor->opaque, &compositor->opaque,
&surface_opaque);
- if (pixman_region32_not_empty(&surface->state.damage))
+ surface_damage = &view->surface->state.damage;
+
+ if (pixman_region32_not_empty(surface_damage))
{
- renderer_flush_surface(surface);
+ renderer_flush_view(view);
/* Translate surface damage to global coordinates. */
- pixman_region32_translate(&surface->state.damage,
- surface->geometry.x,
- surface->geometry.y);
+ pixman_region32_translate
+ (surface_damage, view->base.geometry.x, view->base.geometry.y);
/* Add the surface damage to the compositor damage. */
pixman_region32_union(&compositor->damage, &compositor->damage,
- &surface->state.damage);
- pixman_region32_clear(&surface->state.damage);
+ surface_damage);
+ pixman_region32_clear(surface_damage);
}
if (view->border.damaged)
{
- pixman_region32_t border_region, surface_region;
+ pixman_region32_t border_region, view_region;
pixman_region32_init_with_extents(&border_region, &view->extents);
pixman_region32_init_rect
- (&surface_region, surface->geometry.x, surface->geometry.y,
- surface->geometry.width, surface->geometry.height);
+ (&view_region, view->base.geometry.x, view->base.geometry.y,
+ view->base.geometry.width, view->base.geometry.height);
pixman_region32_subtract(&border_region, &border_region,
- &surface_region);
+ &view_region);
pixman_region32_union(&compositor->damage, &compositor->damage,
&border_region);
pixman_region32_fini(&border_region);
- pixman_region32_fini(&surface_region);
+ pixman_region32_fini(&view_region);
view->border.damaged = false;
}
@@ -527,9 +462,9 @@ static void repaint_screen(struct swc_compositor * compositor,
target.geometry.y = screen->base.geometry.y + output->framebuffer_plane.y;
target.geometry.width = target.buffer->width;
target.geometry.height = target.buffer->height;
+ target.mask = swc_screen_mask(screen);
- renderer_repaint(&target, damage, &base_damage,
- &compositor->surfaces);
+ renderer_repaint(&target, damage, &base_damage, &compositor->views);
pixman_region32_fini(&base_damage);
@@ -607,20 +542,20 @@ static void handle_focus(struct swc_pointer * pointer)
{
/* XXX: Temporary hack */
struct swc_compositor * compositor = swc.compositor;
- struct swc_surface * surface;
+ struct view * view;
int32_t x, y;
- wl_list_for_each(surface, &compositor->surfaces, link)
+ wl_list_for_each(view, &compositor->views, link)
{
x = wl_fixed_to_int(pointer->x);
y = wl_fixed_to_int(pointer->y);
- if (swc_rectangle_contains_point(&surface->geometry, x, y)
- && pixman_region32_contains_point(&surface->state.input,
- x - surface->geometry.x,
- y - surface->geometry.y, NULL))
+ if (swc_rectangle_contains_point(&view->base.geometry, x, y)
+ && pixman_region32_contains_point(&view->surface->state.input,
+ x - view->base.geometry.x,
+ y - view->base.geometry.y, NULL))
{
- swc_pointer_set_focus(pointer, surface);
+ swc_pointer_set_focus(pointer, view->surface);
return;
}
}
@@ -645,14 +580,14 @@ static void handle_drm_event(struct wl_listener * listener, void * data)
case SWC_DRM_PAGE_FLIP:
{
struct swc_drm_event_data * event_data = event->data;
- struct swc_surface * surface;
+ struct view * view;
compositor->pending_flips &= ~SWC_OUTPUT_MASK(event_data->output);
if (compositor->pending_flips == 0)
{
- wl_list_for_each(surface, &compositor->surfaces, link)
- swc_view_frame(surface->view, event_data->time);
+ wl_list_for_each(view, &compositor->views, link)
+ swc_view_frame(&view->base, event_data->time);
}
/* If we had scheduled updates that couldn't run because we were
@@ -744,7 +679,7 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
pixman_region32_init(&compositor->damage);
pixman_region32_init(&compositor->opaque);
- wl_list_init(&compositor->surfaces);
+ wl_list_init(&compositor->views);
swc_add_key_binding(SWC_MOD_CTRL | SWC_MOD_ALT, XKB_KEY_BackSpace,
&handle_terminate, display);
diff --git a/libswc/compositor.h b/libswc/compositor.h
@@ -10,7 +10,7 @@ struct swc_screen_internal;
struct swc_compositor
{
struct wl_display * display;
- struct wl_list surfaces;
+ struct wl_list views;
/* Internal state related to repainting the screen. */
struct
diff --git a/libswc/pointer.c b/libswc/pointer.c
@@ -1,6 +1,7 @@
#include "pointer.h"
#include "event.h"
#include "util.h"
+#include "view.h"
#include <stdio.h>
#include <assert.h>
@@ -19,8 +20,8 @@ static void enter(struct swc_input_focus_handler * handler,
display = wl_client_get_display(client);
serial = wl_display_next_serial(display);
- surface_x = pointer->x - wl_fixed_from_int(surface->geometry.x);
- surface_y = pointer->y - wl_fixed_from_int(surface->geometry.y);
+ surface_x = pointer->x - wl_fixed_from_int(surface->view->geometry.x);
+ surface_y = pointer->y - wl_fixed_from_int(surface->view->geometry.y);
printf("-> pointer.enter: %p (%d, %d)\n", resource, surface_x, surface_y);
wl_pointer_send_enter(resource, serial, surface->resource,
@@ -135,8 +136,6 @@ static void set_cursor(struct wl_client * client,
if (surface)
{
- surface->geometry.x = wl_fixed_to_int(pointer->x) - hotspot_x;
- surface->geometry.y = wl_fixed_to_int(pointer->y) - hotspot_y;
wl_resource_add_destroy_listener(surface->resource,
&pointer->cursor.destroy_listener);
}
@@ -218,20 +217,12 @@ void swc_pointer_handle_relative_motion
{
wl_fixed_t surface_x, surface_y;
surface_x = pointer->x
- - wl_fixed_from_int(pointer->focus.surface->geometry.x);
+ - wl_fixed_from_int(pointer->focus.surface->view->geometry.x);
surface_y = pointer->y
- - wl_fixed_from_int(pointer->focus.surface->geometry.y);
+ - wl_fixed_from_int(pointer->focus.surface->view->geometry.y);
wl_pointer_send_motion(pointer->focus.resource, time,
surface_x, surface_y);
-
- if (pointer->cursor.surface)
- {
- swc_surface_move
- (pointer->cursor.surface,
- wl_fixed_to_int(pointer->x) - pointer->cursor.hotspot_x,
- wl_fixed_to_int(pointer->y) - pointer->cursor.hotspot_y);
- }
}
}
diff --git a/libswc/shell_surface.c b/libswc/shell_surface.c
@@ -26,6 +26,7 @@
#include "swc.h"
#include "surface.h"
#include "util.h"
+#include "view.h"
#include "window.h"
#include <stdlib.h>
@@ -87,8 +88,8 @@ static void set_transient(struct wl_client * client,
= wl_resource_get_user_data(resource);
struct swc_surface * parent = wl_resource_get_user_data(parent_resource);
- swc_surface_move(shell_surface->window.surface,
- parent->geometry.x + x, parent->geometry.y + y);
+ swc_view_move(shell_surface->window.surface->view,
+ parent->view->geometry.x + x, parent->view->geometry.y + y);
swc_compositor_surface_show(shell_surface->window.surface);
/* XXX: Handle transient */
@@ -111,8 +112,8 @@ static void set_popup(struct wl_client * client, struct wl_resource * resource,
= wl_resource_get_user_data(resource);
struct swc_surface * parent = wl_resource_get_user_data(parent_resource);
- swc_surface_move(shell_surface->window.surface,
- parent->geometry.x + x, parent->geometry.y + y);
+ swc_view_move(shell_surface->window.surface->view,
+ parent->view->geometry.x + x, parent->view->geometry.y + y);
swc_compositor_surface_show(shell_surface->window.surface);
/* XXX: Handle popup */
diff --git a/libswc/surface.c b/libswc/surface.c
@@ -24,7 +24,10 @@
#include "surface.h"
#include "buffer.h"
#include "event.h"
+#include "internal.h"
+#include "output.h"
#include "region.h"
+#include "screen.h"
#include "util.h"
#include "view.h"
#include "wayland_buffer.h"
@@ -33,37 +36,6 @@
#include <stdio.h>
#include <wld/wld.h>
-static void set_size(struct swc_surface * surface,
- uint32_t width, uint32_t height)
-{
- /* Check if the surface was resized. */
- if (width != surface->geometry.width || height != surface->geometry.height)
- {
- struct swc_surface_event_data data = {
- .surface = surface,
- .resize = {
- .old_width = surface->geometry.width,
- .old_height = surface->geometry.height,
- .new_width = width,
- .new_height = height
- }
- };
-
- surface->geometry.width = width;
- surface->geometry.height = height;
-
- pixman_region32_intersect_rect
- (&surface->state.opaque, &surface->state.opaque,
- 0, 0, width, height);
- pixman_region32_intersect_rect
- (&surface->state.damage, &surface->state.damage,
- 0, 0, width, height);
-
- swc_send_event(&surface->event_signal,
- SWC_SURFACE_EVENT_TYPE_RESIZE, &data);
- }
-}
-
/**
* Removes a buffer from a surface state.
*/
@@ -73,21 +45,12 @@ static void handle_buffer_destroy(struct wl_listener * listener, void * data)
state = CONTAINER_OF(listener, typeof(*state), buffer_destroy_listener);
state->buffer = NULL;
-
- if (state->current)
- {
- struct swc_surface * surface;
-
- surface = CONTAINER_OF(state, typeof(*surface), state);
- set_size(surface, 0, 0);
- }
}
-static void state_initialize(struct swc_surface_state * state, bool current)
+static void state_initialize(struct swc_surface_state * state)
{
state->buffer = NULL;
state->buffer_destroy_listener.notify = &handle_buffer_destroy;
- state->current = current;
pixman_region32_init(&state->damage);
pixman_region32_init(&state->opaque);
@@ -232,6 +195,7 @@ static void set_input_region(struct wl_client * client,
static void commit(struct wl_client * client, struct wl_resource * resource)
{
struct swc_surface * surface = wl_resource_get_user_data(resource);
+ struct wld_buffer * buffer;
/* Attach */
if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH)
@@ -243,24 +207,17 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
swc_wayland_buffer_release(current_buffer);
state_set_buffer(&surface->state, surface->pending.state.buffer);
-
- /* Determine size of buffer. */
- if (current_buffer)
- {
- set_size(surface,
- current_buffer->wld->width, current_buffer->wld->height);
- }
- else
- set_size(surface, 0, 0);
}
+ buffer = surface->state.buffer ? surface->state.buffer->wld : NULL;
+
/* Damage */
if (surface->pending.commit & SWC_SURFACE_COMMIT_DAMAGE)
{
pixman_region32_intersect_rect(&surface->pending.state.damage,
&surface->pending.state.damage, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ buffer ? buffer->width : 0,
+ buffer ? buffer->height : 0);
pixman_region32_union(&surface->state.damage, &surface->state.damage,
&surface->pending.state.damage);
pixman_region32_clear(&surface->pending.state.damage);
@@ -271,8 +228,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
{
pixman_region32_intersect_rect(&surface->state.opaque,
&surface->pending.state.opaque, 0, 0,
- surface->geometry.width,
- surface->geometry.height);
+ buffer ? buffer->width : 0,
+ buffer ? buffer->height : 0);
}
/* Input */
@@ -293,8 +250,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
if (surface->view)
{
if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH)
- surface->view->impl->attach(surface->view, surface->state.buffer);
- surface->view->impl->update(surface->view);
+ swc_view_attach(surface->view, surface->state.buffer);
+ swc_view_update(surface->view);
}
surface->pending.commit = 0;
@@ -335,6 +292,9 @@ static void surface_destroy(struct wl_resource * resource)
state_finish(&surface->state);
state_finish(&surface->pending.state);
+ if (surface->view)
+ wl_list_remove(&surface->view_listener.link);
+
printf("freeing surface %p\n", surface);
free(surface);
}
@@ -362,6 +322,46 @@ static void handle_view_event(struct wl_listener * listener, void * data)
wl_list_init(&surface->state.frame_callbacks);
break;
}
+ case SWC_VIEW_EVENT_SCREENS_CHANGED:
+ {
+ struct swc_screen_internal * screen;
+ struct swc_output * output;
+ struct wl_client * client;
+ struct wl_resource * resource;
+ uint32_t entered = event_data->screens_changed.entered,
+ left = event_data->screens_changed.left;
+
+ client = wl_resource_get_client(surface->resource);
+
+ wl_list_for_each(screen, &swc.screens, link)
+ {
+ if (!((entered | left) & swc_screen_mask(screen)))
+ continue;
+
+ wl_list_for_each(output, &screen->outputs, link)
+ {
+ resource = wl_resource_find_for_client
+ (&output->resources, client);
+
+ if (resource)
+ {
+ if (entered & swc_screen_mask(screen))
+ wl_surface_send_enter(surface->resource, resource);
+ else if (left & swc_screen_mask(screen))
+ wl_surface_send_leave(surface->resource, resource);
+ }
+ }
+ }
+ break;
+ }
+ case SWC_VIEW_EVENT_RESIZED:
+ pixman_region32_intersect_rect
+ (&surface->state.opaque, &surface->state.opaque, 0, 0,
+ surface->view->geometry.width, surface->view->geometry.height);
+ pixman_region32_intersect_rect
+ (&surface->state.damage, &surface->state.damage, 0, 0,
+ surface->view->geometry.width, surface->view->geometry.height);
+ break;
}
}
@@ -383,19 +383,13 @@ struct swc_surface * swc_surface_new(struct wl_client * client,
return NULL;
/* Initialize the surface. */
- surface->screens = 0;
- surface->geometry.x = 0;
- surface->geometry.y = 0;
- surface->geometry.width = 0;
- surface->geometry.height = 0;
surface->pending.commit = 0;
surface->window = NULL;
surface->view = NULL;
surface->view_listener.notify = &handle_view_event;
- surface->view_state = NULL;
- state_initialize(&surface->state, true);
- state_initialize(&surface->pending.state, false);
+ state_initialize(&surface->state);
+ state_initialize(&surface->pending.state);
wl_signal_init(&surface->event_signal);
@@ -425,20 +419,8 @@ void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view)
if (view)
{
wl_signal_add(&view->event_signal, &surface->view_listener);
- surface->view->impl->attach(surface->view, surface->state.buffer);
- surface->view->impl->update(surface->view);
+ swc_view_attach(view, surface->state.buffer);
+ swc_view_update(surface->view);
}
}
-void swc_surface_update(struct swc_surface * surface)
-{
- if (surface->view)
- surface->view->impl->update(surface->view);
-}
-
-void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y)
-{
- if (surface->view)
- surface->view->impl->move(surface->view, x, y);
-}
-
diff --git a/libswc/surface.h b/libswc/surface.h
@@ -24,8 +24,7 @@
#ifndef SWC_SURFACE_H
#define SWC_SURFACE_H
-#include "swc.h"
-
+#include <stdbool.h>
#include <wayland-server.h>
#include <pixman.h>
@@ -58,7 +57,6 @@ struct swc_surface_state
{
struct swc_buffer * buffer;
struct wl_listener buffer_destroy_listener;
- bool current;
/* The region that needs to be repainted. */
pixman_region32_t damage;
@@ -88,10 +86,6 @@ struct swc_surface
struct swc_window * window;
struct swc_view * view;
struct wl_listener view_listener;
- void * view_state;
-
- uint32_t screens;
- struct swc_rectangle geometry;
struct wl_signal event_signal;
struct wl_list link;
@@ -102,9 +96,5 @@ struct swc_surface * swc_surface_new(struct wl_client * client,
void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view);
-void swc_surface_update(struct swc_surface * surface);
-
-void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y);
-
#endif
diff --git a/libswc/view.c b/libswc/view.c
@@ -22,17 +22,137 @@
*/
#include "view.h"
+#include "buffer.h"
#include "event.h"
+#include "internal.h"
+#include "screen.h"
+#include "util.h"
+
+#include <wld/wld.h>
+
+static void update_screens(struct swc_view * view)
+{
+ struct swc_view_event_data data = { .view = view };
+ uint32_t old = view->screens, new = 0;
+ struct swc_screen_internal * screen;
+
+ if (view->visible)
+ {
+ wl_list_for_each(screen, &swc.screens, link)
+ {
+ if (swc_rectangle_overlap(&screen->base.geometry, &view->geometry))
+ new |= swc_screen_mask(screen);
+ }
+ }
+
+ if (new == old)
+ return;
+
+ view->screens = new;
+
+ data.screens_changed.entered = new & ~old;
+ data.screens_changed.left = old & ~new;
+ swc_send_event(&view->event_signal, SWC_VIEW_EVENT_SCREENS_CHANGED, &data);
+}
+
+static void set_size(struct swc_view * view, uint32_t width, uint32_t height)
+{
+ if (view->geometry.width != width || view->geometry.height != height)
+ {
+ struct swc_view_event_data data = { .view = view };
+
+ if (view->impl->resize)
+ view->impl->resize(view);
+
+ view->geometry.width = width;
+ view->geometry.height = height;
+ update_screens(view);
+
+ swc_send_event(&view->event_signal, SWC_VIEW_EVENT_RESIZED, &data);
+ }
+}
+
+static void handle_buffer_destroy(struct wl_listener * listener, void * data)
+{
+ struct swc_view * view
+ = CONTAINER_OF(listener, typeof(*view), buffer_destroy_listener);
+
+ view->impl->attach(view, NULL);
+ view->buffer = NULL;
+ set_size(view, 0, 0);
+}
void swc_view_initialize(struct swc_view * view,
const struct swc_view_impl * impl)
{
view->impl = impl;
+ view->visible = true;
+ view->geometry.x = 0;
+ view->geometry.y = 0;
+ view->geometry.width = 0;
+ view->geometry.height = 0;
+ view->buffer = NULL;
+ view->buffer_destroy_listener.notify = &handle_buffer_destroy;
+ view->screens = 0;
wl_signal_init(&view->event_signal);
}
void swc_view_finalize(struct swc_view * view)
{
+ if (view->buffer)
+ wl_list_remove(&view->buffer_destroy_listener.link);
+}
+
+bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer)
+{
+ if (view->impl->attach(view, buffer))
+ {
+ if (view->buffer)
+ wl_list_remove(&view->buffer_destroy_listener.link);
+
+ if (buffer)
+ {
+ wl_signal_add(&buffer->destroy_signal,
+ &view->buffer_destroy_listener);
+ set_size(view, buffer->wld->width, buffer->wld->height);
+ }
+ else
+ set_size(view, 0, 0);
+
+ view->buffer = buffer;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool swc_view_update(struct swc_view * view)
+{
+ return view->impl->update(view);
+}
+
+bool swc_view_move(struct swc_view * view, int32_t x, int32_t y)
+{
+ struct swc_view_event_data data = { .view = view };
+
+ if (x == view->geometry.x && y == view->geometry.y)
+ return true;
+
+ if (!view->impl->move || !view->impl->move(view, x, y))
+ return false;
+
+ view->geometry.x = x;
+ view->geometry.y = y;
+ update_screens(view);
+ swc_send_event(&view->event_signal, SWC_VIEW_EVENT_MOVED, &data);
+
+ return true;
+}
+
+void swc_view_set_visibility(struct swc_view * view, bool visible)
+{
+ view->visible = visible;
+ update_screens(view);
}
void swc_view_frame(struct swc_view * view, uint32_t time)
diff --git a/libswc/view.h b/libswc/view.h
@@ -26,12 +26,20 @@
#include "swc.h"
-struct swc_buffer;
-
enum swc_view_event
{
/* Sent when the view has displayed the next frame. */
SWC_VIEW_EVENT_FRAME,
+
+ /* Sent when the origin of the view has moved. */
+ SWC_VIEW_EVENT_MOVED,
+
+ /* Sent when the view's size changes. This occurs when a buffer of
+ * different dimensions is attached to the view. */
+ SWC_VIEW_EVENT_RESIZED,
+
+ /* Sent when the set of screens the view is visible on changes. */
+ SWC_VIEW_EVENT_SCREENS_CHANGED
};
struct swc_view_event_data
@@ -43,6 +51,11 @@ struct swc_view_event_data
{
uint32_t time;
} frame;
+
+ struct
+ {
+ uint32_t left, entered;
+ } screens_changed;
};
};
@@ -51,21 +64,28 @@ struct swc_view
const struct swc_view_impl * impl;
struct wl_signal event_signal;
+ bool visible;
+ uint32_t screens;
+
+ struct swc_rectangle geometry;
+ struct swc_buffer * buffer;
+ struct wl_listener buffer_destroy_listener;
};
struct swc_view_impl
{
- /* Called when a source is removed from the view. */
- void (* remove)(struct swc_view * view);
+ /* Called when the view should present a new frame. */
+ bool (* update)(struct swc_view * view);
/* Called when a new buffer is attached to the view. */
- void (* attach)(struct swc_view * view, struct swc_buffer * buffer);
+ bool (* attach)(struct swc_view * view, struct swc_buffer * buffer);
- /* Called when the view should present a new frame. */
- void (* update)(struct swc_view * view);
+ bool (* move)(struct swc_view * view, int32_t x, int32_t y);
- /* Move the view to the specified coordinates. */
- void (* move)(struct swc_view * view, int32_t x, int32_t y);
+ void (* resize)(struct swc_view * view);
+
+ /* Called when a source is removed from the view. */
+ void (* remove)(struct swc_view * view);
};
void swc_view_initialize(struct swc_view * view,
@@ -73,6 +93,10 @@ void swc_view_initialize(struct swc_view * view,
void swc_view_finalize(struct swc_view * view);
+bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer);
+bool swc_view_update(struct swc_view * view);
+bool swc_view_move(struct swc_view * view, int32_t x, int32_t y);
+void swc_view_set_visibility(struct swc_view * view, bool visible);
void swc_view_frame(struct swc_view * view, uint32_t time);
#endif
diff --git a/libswc/window.c b/libswc/window.c
@@ -29,6 +29,7 @@
#include "seat.h"
#include "swc.h"
#include "util.h"
+#include "view.h"
#include <stdlib.h>
#include <string.h>
@@ -97,7 +98,7 @@ void swc_window_set_geometry(struct swc_window * window,
if (INTERNAL(window)->impl->configure)
INTERNAL(window)->impl->configure(window, geometry);
- swc_surface_move(INTERNAL(window)->surface, geometry->x, geometry->y);
+ swc_view_move(INTERNAL(window)->surface->view, geometry->x, geometry->y);
}
EXPORT
diff --git a/libswc/xwm.c b/libswc/xwm.c
@@ -27,6 +27,7 @@
#include "surface.h"
#include "swc.h"
#include "util.h"
+#include "view.h"
#include "window.h"
#include <stdio.h>
@@ -341,7 +342,7 @@ void swc_xwm_manage_window(xcb_window_t id, struct swc_surface * surface)
if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
geometry_cookie, NULL)))
{
- swc_surface_move(surface, geometry_reply->x, geometry_reply->y);
+ swc_view_move(surface->view, geometry_reply->x, geometry_reply->y);
}
if (entry->override_redirect)