summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPekka Paalanen <ppaalanen@gmail.com>2013-04-25 13:57:49 +0300
committerKristian Høgsberg <krh@bitplanet.net>2013-05-10 14:35:53 -0400
commit40cb67b2aca16ce650fff95a005c86d766886bd0 (patch)
treeb44c5fd4e8a25120a20c2b2bc6fa25b7e319104c
parent35e82631b61a41fc8527258bd00afaf17990b0ed (diff)
window: implement per-surface redraws
Add redraw_needed flag to all surfaces, in addition to having one in window. The window redraw_needed flag is changed to force a redraw of the whole window, regardless of frame events. widget_schedule_redraw() now schedules the redraw only for the surface, where the widget is on. window_schedule_redraw() is equivalent to scheduling a redraw for all (sub-)surfaces of the window. We still use only one deferred task for all redraws. surface_redraw() will skip the redraw, if the window does not force a redraw and the surface does not need a redraw. It will also skip the redraw, if the frame callback from the previous redraw has not triggered yet. When the frame callback later arrives, the redraw task will be scheduled, if the surface still needs a redraw. If the window forces a redraw, the redraw is executed even if there is a pending frame callback. This is for resizing: resizing should trigger a window repaint, as it really wants to update all surfaces in one go, to apply possible sub-surface size and position changes. Resizing is the only thing that makes a window force a redraw. With this change, subsurfaces demo can avoid repainting the cairo sub-surface while still animating the GL sub-surface. Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
-rw-r--r--clients/window.c88
1 files changed, 61 insertions, 27 deletions
diff --git a/clients/window.c b/clients/window.c
index 30bb71e..9bcf7ff 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -195,6 +195,8 @@ struct surface {
int synchronized_default;
struct toysurface *toysurface;
struct widget *widget;
+ int redraw_needed;
+ struct wl_callback *frame_cb;
struct rectangle allocation;
struct rectangle server_allocation;
@@ -220,8 +222,8 @@ struct window {
struct rectangle pending_allocation;
int x, y;
int resize_edges;
- int redraw_scheduled;
int redraw_needed;
+ int redraw_task_scheduled;
struct task redraw_task;
int resize_needed;
int saved_type;
@@ -242,7 +244,6 @@ struct window {
struct surface *main_surface;
struct wl_shell_surface *shell_surface;
- struct wl_callback *frame_cb;
struct frame *frame;
@@ -1311,6 +1312,9 @@ static void frame_destroy(struct frame *frame);
static void
surface_destroy(struct surface *surface)
{
+ if (surface->frame_cb)
+ wl_callback_destroy(surface->frame_cb);
+
if (surface->input_region)
wl_region_destroy(surface->input_region);
@@ -1337,8 +1341,7 @@ window_destroy(struct window *window)
struct window_output *window_output;
struct window_output *window_output_tmp;
- if (window->redraw_scheduled)
- wl_list_remove(&window->redraw_task.link);
+ wl_list_remove(&window->redraw_task.link);
wl_list_for_each(input, &display->input_list, link) {
if (input->pointer_focus == window)
@@ -1365,8 +1368,6 @@ window_destroy(struct window *window)
wl_list_remove(&window->link);
- if (window->frame_cb)
- wl_callback_destroy(window->frame_cb);
free(window->title);
free(window);
}
@@ -1593,10 +1594,14 @@ widget_set_axis_handler(struct widget *widget,
widget->axis_handler = handler;
}
+static void
+window_schedule_redraw_task(struct window *window);
+
void
widget_schedule_redraw(struct widget *widget)
{
- window_schedule_redraw(widget->window);
+ widget->surface->redraw_needed = 1;
+ window_schedule_redraw_task(widget->window);
}
cairo_surface_t *
@@ -3335,6 +3340,7 @@ idle_resize(struct window *window)
struct surface *surface;
window->resize_needed = 0;
+ window->redraw_needed = 1;
widget_set_allocation(window->main_surface->widget,
window->pending_allocation.x,
@@ -3450,14 +3456,14 @@ widget_redraw(struct widget *widget)
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
- struct window *window = data;
+ struct surface *surface = data;
- assert(callback == window->frame_cb);
+ assert(callback == surface->frame_cb);
wl_callback_destroy(callback);
- window->frame_cb = 0;
- window->redraw_scheduled = 0;
- if (window->redraw_needed)
- window_schedule_redraw(window);
+ surface->frame_cb = NULL;
+
+ if (surface->redraw_needed || surface->window->redraw_needed)
+ window_schedule_redraw_task(surface->window);
}
static const struct wl_callback_listener listener = {
@@ -3465,6 +3471,29 @@ static const struct wl_callback_listener listener = {
};
static void
+surface_redraw(struct surface *surface)
+{
+ if (!surface->window->redraw_needed && !surface->redraw_needed)
+ return;
+
+ /* Whole-window redraw forces a redraw even if the previous has
+ * not yet hit the screen.
+ */
+ if (surface->frame_cb) {
+ if (!surface->window->redraw_needed)
+ return;
+
+ wl_callback_destroy(surface->frame_cb);
+ }
+
+ surface->frame_cb = wl_surface_frame(surface->surface);
+ wl_callback_add_listener(surface->frame_cb, &listener, surface);
+
+ surface->redraw_needed = 0;
+ widget_redraw(surface->widget);
+}
+
+static void
idle_redraw(struct task *task, uint32_t events)
{
struct window *window = container_of(task, struct window, redraw_task);
@@ -3474,32 +3503,41 @@ idle_redraw(struct task *task, uint32_t events)
idle_resize(window);
wl_list_for_each(surface, &window->subsurface_list, link)
- widget_redraw(surface->widget);
+ surface_redraw(surface);
window->redraw_needed = 0;
wl_list_init(&window->redraw_task.link);
+ window->redraw_task_scheduled = 0;
- 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
-window_schedule_redraw(struct window *window)
+static void
+window_schedule_redraw_task(struct window *window)
{
- window->redraw_needed = 1;
if (window->configure_requests)
return;
- if (!window->redraw_scheduled) {
+ if (!window->redraw_task_scheduled) {
window->redraw_task.run = idle_redraw;
display_defer(window->display, &window->redraw_task);
- window->redraw_scheduled = 1;
+ window->redraw_task_scheduled = 1;
}
}
+void
+window_schedule_redraw(struct window *window)
+{
+ struct surface *surface;
+
+ wl_list_for_each(surface, &window->subsurface_list, link)
+ surface->redraw_needed = 1;
+
+ window_schedule_redraw_task(window);
+}
+
int
window_is_fullscreen(struct window *window)
{
@@ -3527,13 +3565,9 @@ window_defer_redraw_until_configure(struct window* window)
{
struct wl_callback *callback;
- if (window->redraw_scheduled) {
+ if (window->redraw_task_scheduled) {
wl_list_remove(&window->redraw_task.link);
- window->redraw_scheduled = 0;
- }
- if (window->frame_cb) {
- wl_callback_destroy(window->frame_cb);
- window->frame_cb = 0;
+ window->redraw_task_scheduled = 0;
}
callback = wl_display_sync(window->display->display);