commit d95b8178ddb4304c7c3ee325bdae366b81cb6b89
parent 3333dfd86da6a407fd39ad77d2f5cb85cd8ba824
Author: Michael Forney <mforney@mforney.org>
Date: Fri, 7 Feb 2014 23:28:55 -0800
view: Make view implementations explicitly change view state
This way, the framebuffer plane can keep a constant size (even if an
oversized buffer is attached). Additionally this enables some tricks for
ensuring smooth move+resize (common operation for tiling window
managers).
Diffstat:
8 files changed, 117 insertions(+), 114 deletions(-)
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -68,6 +68,9 @@ struct view
struct swc_surface * surface;
struct wld_buffer * buffer;
+ /* Whether or not the view is visible (mapped). */
+ bool visible;
+
/* The box that the surface covers (including it's border). */
pixman_box32_t extents;
@@ -426,12 +429,14 @@ static void schedule_updates(uint32_t screens)
compositor.scheduled_updates |= screens;
}
-static bool update(struct swc_view * view)
+static bool update(struct swc_view * base)
{
+ struct view * view = (void *) base;
+
if (!compositor.active || !view->visible)
return false;
- schedule_updates(view->screens);
+ schedule_updates(view->base.screens);
return true;
}
@@ -443,38 +448,36 @@ static bool attach(struct swc_view * base, struct wld_buffer * buffer)
if (!renderer_attach(view, buffer))
return false;
- return true;
-}
-
-static bool move(struct swc_view * base, int32_t x, int32_t y)
-{
- struct view * view = (void *) base;
-
- if (view->base.visible)
+ if (view->visible && view->base.buffer)
{
damage_below_view(view);
update(&view->base);
}
+ swc_view_set_size_from_buffer(&view->base, buffer);
+
return true;
}
-static void resize(struct swc_view * base)
+static bool move(struct swc_view * base, int32_t x, int32_t y)
{
struct view * view = (void *) base;
- if (view->base.visible)
+ if (view->visible)
{
damage_below_view(view);
update(&view->base);
}
+
+ swc_view_set_position(&view->base, x, y);
+
+ return true;
}
const static struct swc_view_impl view_impl = {
.update = &update,
.attach = &attach,
- .move = &move,
- .resize = &resize,
+ .move = &move
};
static void handle_view_event(struct wl_listener * listener, void * data)
@@ -487,22 +490,24 @@ static void handle_view_event(struct wl_listener * listener, void * data)
case SWC_VIEW_EVENT_MOVED:
update_extents(view);
- if (view->base.visible)
+ if (view->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);
+ swc_view_update_screens(&view->base);
update(&view->base);
}
break;
case SWC_VIEW_EVENT_RESIZED:
update_extents(view);
- if (view->base.visible)
+ if (view->visible)
{
damage_below_view(view);
+ swc_view_update_screens(&view->base);
update(&view->base);
}
break;
@@ -519,11 +524,11 @@ bool swc_compositor_add_surface(struct swc_surface * surface)
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->surface = surface;
view->buffer = NULL;
+ view->visible = false;
view->extents.x1 = 0;
view->extents.y1 = 0;
view->extents.x2 = 0;
@@ -560,7 +565,7 @@ void swc_compositor_surface_show(struct swc_surface * surface)
if (view->base.impl != &view_impl)
return;
- if (view->base.visible)
+ if (view->visible)
return;
printf("showing surface %u\n", wl_resource_get_id(surface->resource));
@@ -569,8 +574,10 @@ void swc_compositor_surface_show(struct swc_surface * surface)
* surface gets moved before that. */
pixman_region32_clear(&view->clip);
+ view->visible = true;
+ swc_view_update_screens(&view->base);
+
damage_view(view);
- swc_view_set_visibility(&view->base, true);
update(&view->base);
wl_list_insert(&compositor.views, &view->link);
}
@@ -582,15 +589,16 @@ void swc_compositor_surface_hide(struct swc_surface * surface)
if (view->base.impl != &view_impl)
return;
- if (!view->base.visible)
+ if (!view->visible)
return;
/* Update all the outputs the surface was on. */
update(&view->base);
damage_below_view(view);
- swc_view_set_visibility(&view->base, false);
wl_list_remove(&view->link);
+ swc_view_set_screens(&view->base, 0);
+ view->visible = false;
}
void swc_compositor_surface_set_border_width(struct swc_surface * surface,
diff --git a/libswc/cursor_plane.c b/libswc/cursor_plane.c
@@ -68,6 +68,8 @@ static bool attach(struct swc_view * view, struct wld_buffer * buffer)
}
}
+ swc_view_set_size_from_buffer(view, buffer);
+
return true;
}
@@ -76,13 +78,14 @@ static bool move(struct swc_view * view, int32_t x, int32_t y)
struct swc_cursor_plane * plane = CONTAINER_OF(view, typeof(*plane), view);
if (drmModeMoveCursor(swc.drm->fd, plane->crtc,
- x - view->screen->base.geometry.x,
- y - view->screen->base.geometry.y) != 0)
+ x - plane->origin->x, y - plane->origin->y) != 0)
{
ERROR("Could not move cursor: %s\n", strerror(errno));
return false;
}
+ swc_view_set_position(view, x, y);
+
return true;
}
@@ -107,11 +110,13 @@ static void handle_launch_event(struct wl_listener * listener, void * data)
}
}
-bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane, uint32_t crtc)
+bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane, uint32_t crtc,
+ const struct swc_rectangle * origin)
{
if (drmModeSetCursor(swc.drm->fd, crtc, 0, 0, 0) != 0)
return false;
+ plane->origin = origin;
plane->crtc = crtc;
plane->launch_listener.notify = &handle_launch_event;
wl_signal_add(&swc.launch->event_signal, &plane->launch_listener);
diff --git a/libswc/cursor_plane.h b/libswc/cursor_plane.h
@@ -29,12 +29,13 @@
struct swc_cursor_plane
{
struct swc_view view;
+ const struct swc_rectangle * origin;
uint32_t crtc;
struct wl_listener launch_listener;
};
-bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane,
- uint32_t crtc);
+bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane, uint32_t crtc,
+ const struct swc_rectangle * origin);
void swc_cursor_plane_finalize(struct swc_cursor_plane * plane);
diff --git a/libswc/framebuffer_plane.c b/libswc/framebuffer_plane.c
@@ -148,6 +148,8 @@ static bool attach(struct swc_view * view, struct wld_buffer * buffer)
static bool move(struct swc_view * view, int32_t x, int32_t y)
{
+ swc_view_set_position(view, x, y);
+
return true;
}
diff --git a/libswc/pointer.c b/libswc/pointer.c
@@ -104,11 +104,15 @@ static bool attach(struct swc_view * view, struct wld_buffer * buffer)
/* TODO: Send an early release to the buffer */
+ swc_view_set_size_from_buffer(view, buffer);
+
return true;
}
static bool move(struct swc_view * view, int32_t x, int32_t y)
{
+ swc_view_set_position(view, x, y);
+
return true;
}
@@ -135,6 +139,11 @@ static void handle_view_event(struct wl_listener * listener, void * data)
swc_view_move(&screen->planes.cursor.view,
view->geometry.x, view->geometry.y);
}
+
+ swc_view_update_screens(view);
+ break;
+ case SWC_VIEW_EVENT_RESIZED:
+ swc_view_update_screens(view);
break;
case SWC_VIEW_EVENT_SCREENS_CHANGED:
wl_list_for_each(screen, &swc.screens, link)
diff --git a/libswc/screen.c b/libswc/screen.c
@@ -80,15 +80,13 @@ struct screen * screen_new(uint32_t crtc, struct swc_output * output)
goto error1;
}
- if (!swc_cursor_plane_initialize(&screen->planes.cursor, crtc))
+ if (!swc_cursor_plane_initialize(&screen->planes.cursor, crtc,
+ &screen->base.geometry))
{
ERROR("Failed to initialize cursor plane\n");
goto error2;
}
- screen->planes.framebuffer.view.screen = screen;
- screen->planes.cursor.view.screen = screen;
-
swc_view_move(&screen->planes.framebuffer.view, x, 0);
screen->base.geometry = screen->planes.framebuffer.view.geometry;
screen->base.usable_geometry = screen->base.geometry;
diff --git a/libswc/view.c b/libswc/view.c
@@ -29,53 +29,10 @@
#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 screen * screen;
-
- if (view->visible)
- {
- wl_list_for_each(screen, &swc.screens, link)
- {
- if (swc_rectangle_overlap(&screen->base.geometry, &view->geometry))
- new |= 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);
- }
-}
-
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;
@@ -99,12 +56,7 @@ bool swc_view_attach(struct swc_view * view, struct wld_buffer * buffer)
wld_buffer_unreference(view->buffer);
if (buffer)
- {
wld_buffer_reference(buffer);
- set_size(view, buffer->width, buffer->height);
- }
- else
- set_size(view, 0, 0);
view->buffer = buffer;
return true;
@@ -120,26 +72,71 @@ bool swc_view_update(struct swc_view * view)
bool swc_view_move(struct swc_view * view, int32_t x, int32_t y)
{
+ return view->impl->move(view, x, y);
+}
+
+void swc_view_set_position(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;
+ return;
view->geometry.x = x;
view->geometry.y = y;
- update_screens(view);
swc_send_event(&view->event_signal, SWC_VIEW_EVENT_MOVED, &data);
+}
+
+void swc_view_set_size(struct swc_view * view, uint32_t width, uint32_t height)
+{
+ struct swc_view_event_data data = { .view = view };
+
+ if (view->geometry.width == width && view->geometry.height == height)
+ return;
+
+ view->geometry.width = width;
+ view->geometry.height = height;
+ swc_send_event(&view->event_signal, SWC_VIEW_EVENT_RESIZED, &data);
+}
+
+void swc_view_set_size_from_buffer(struct swc_view * view,
+ struct wld_buffer * buffer)
+{
+ if (buffer)
+ swc_view_set_size(view, buffer->width, buffer->height);
+ else
+ swc_view_set_size(view, 0, 0);
+}
+
+void swc_view_set_screens(struct swc_view * view, uint32_t screens)
+{
+ if (view->screens == screens)
+ return;
+
+ struct swc_view_event_data data = {
+ .view = view,
+ .screens_changed = {
+ .entered = screens & ~view->screens,
+ .left = view->screens & ~screens
+ }
+ };
- return true;
+ view->screens = screens;
+ swc_send_event(&view->event_signal, SWC_VIEW_EVENT_SCREENS_CHANGED, &data);
}
-void swc_view_set_visibility(struct swc_view * view, bool visible)
+void swc_view_update_screens(struct swc_view * view)
{
- view->visible = visible;
- update_screens(view);
+ uint32_t screens = 0;
+ struct screen * screen;
+
+ wl_list_for_each(screen, &swc.screens, link)
+ {
+ if (swc_rectangle_overlap(&screen->base.geometry, &view->geometry))
+ screens |= screen_mask(screen);
+ }
+
+ swc_view_set_screens(view, screens);
}
void swc_view_frame(struct swc_view * view, uint32_t time)
diff --git a/libswc/view.h b/libswc/view.h
@@ -34,8 +34,7 @@ enum
/* 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. */
+ /* Sent when the view's size changes. */
SWC_VIEW_EVENT_RESIZED,
/* Sent when the set of screens the view is visible on changes. */
@@ -82,16 +81,8 @@ struct swc_view
const struct swc_view_impl * impl;
struct wl_signal event_signal;
- bool visible;
- uint32_t screens;
-
struct swc_rectangle geometry;
-
- /**
- * The screen that the view belongs to (for example if framebuffer or
- * cursor plane), or NULL.
- */
- struct screen * screen;
+ uint32_t screens;
struct wld_buffer * buffer;
};
@@ -106,14 +97,6 @@ struct swc_view_impl
bool (* update)(struct swc_view * view);
bool (* attach)(struct swc_view * view, struct wld_buffer * buffer);
bool (* move)(struct swc_view * view, int32_t x, int32_t y);
-
- /**
- * This function indicates to the view that it is about to be resized.
- *
- * The view can use this function to do any necessary damage calculations
- * with the geometry of the view before the resize occurs.
- */
- void (* resize)(struct swc_view * view);
};
/**
@@ -150,14 +133,14 @@ bool swc_view_update(struct swc_view * view);
*/
bool swc_view_move(struct swc_view * view, int32_t x, int32_t y);
-/**
- * Set the visibility flag of the view.
- *
- * This retains the view's geometry, but indicates that it will not be shown
- * when the next frame is finished. This is useful when an unmapped or
- * minimized state is desired.
- */
-void swc_view_set_visibility(struct swc_view * view, bool visible);
+/**** For internal view use only ****/
+
+void swc_view_set_position(struct swc_view * view, int32_t x, int32_t y);
+void swc_view_set_size(struct swc_view * view, uint32_t width, uint32_t height);
+void swc_view_set_size_from_buffer(struct swc_view * view,
+ struct wld_buffer * bufer);
+void swc_view_set_screens(struct swc_view * view, uint32_t screens);
+void swc_view_update_screens(struct swc_view * view);
/**
* Send a new frame event through the view's event signal.