wlt: toolkit: fix resize window stuck in need_resize=true
authorMartin Minarik <minarik11@student.fiit.stuba.sk>
Thu, 24 Jan 2013 15:48:03 +0000 (16:48 +0100)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Thu, 24 Jan 2013 19:13:09 +0000 (20:13 +0100)
The problem is that:
 wnd->w_frame contains a number
and
 wnd->need_frame=true
Therefore schedule_frame() doesn't schedule the callback.
But deleting these checks causes flicker. Further redesign
of the frame sheduling was necessary.

4. frame_callback()
3. do_frame()
3. idle_frame()
2. schedule_frame()
1. wlt_window_set_size()

Please, observe the need_resize variable.
-------------------------------------------------------------------------------
BAD (window stuck on resize):
$3 = {ref = 1, list = {next = 0x659c70, prev = 0x659c70},
  buffer_attached = true, skip_damage = false, need_resize = true,
  w_frame = 0x70d9b0, widget_list = {next = 0x686cb0, prev = 0x6b54d0}}

OK (window not stuck on resize):
$3 = {ref = 1, list = {next = 0x240cc70, prev = 0x240cc70},
  buffer_attached = true, skip_damage = false, need_resize = false,
  w_frame = 0x241bb10, widget_list = {next = 0x2439cb0, prev = 0x2468560}}

-----------------------------------------------------------------------------------

This is the basic idea:

-> time ->
frame callbacks()      *           *           *           *           *           *
wnd->idle_pending ------   ---------   ---------    --------   ---------------------
wnd->need_frame   ---      --- ---     ---          ---        ------ ---
schedule_frame()  *        *   *       *            *          *  *   **
idle_frame()        *        *   *       *            *          *  *   *

This design follows similiar design in weston/clients/window.c

Kmscon                     Weston
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wlt_window_do_redraw() ~~~ shm_surface_swap()
do_frame() ~~~~~~~~~~~~~~~ window_attach_surface()

wnd->idle_pending ~~~~~~~~ window->redraw_scheduled

frame_callback()  ~~~~~~~~ frame_callback()

do_frame()  ~~~~~~~~~~~~~~ idle_redraw()

wlt_window_set_size()
wlt_window_schedule_redraw()
schedule_frame()  ~~~~~~~~ window_schedule_redraw()

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/wlt_toolkit.c

index 41f6d0c..0aa0a97 100644 (file)
@@ -126,7 +126,6 @@ struct wlt_window {
        bool buffer_attached;
        bool skip_damage;
        bool need_resize;
-       bool need_redraw;
        bool need_frame;
        bool idle_pending;
        unsigned int new_width;
@@ -1305,7 +1304,7 @@ static void wlt_window_do_redraw(struct wlt_window *wnd,
 }
 
 static int resize_window(struct wlt_window *wnd, unsigned int width,
-                        unsigned int height, bool force_redraw)
+                        unsigned int height)
 {
        struct shl_dlist *iter;
        struct wlt_widget *widget;
@@ -1351,8 +1350,7 @@ static int resize_window(struct wlt_window *wnd, unsigned int width,
 
        if (width == wnd->buffer.width &&
            height == wnd->buffer.height) {
-               if (force_redraw)
-                       wlt_window_do_redraw(wnd, width, height);
+               wlt_window_do_redraw(wnd, width, height);
                return 0;
        }
 
@@ -1420,26 +1418,18 @@ static const struct wl_callback_listener frame_callback_listener = {
 
 static void do_frame(struct wlt_window *wnd)
 {
-       bool force;
-
-       wnd->idle_pending = false;
        ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd,
                                    EV_NORMAL);
 
        if (wnd->need_resize) {
-               force = wnd->need_redraw;
                wnd->need_frame = true;
                wnd->need_resize = false;
-               wnd->need_redraw = false;
                wnd->w_frame = wl_surface_frame(wnd->w_surface);
                wl_callback_add_listener(wnd->w_frame,
                                         &frame_callback_listener, wnd);
-               resize_window(wnd, wnd->new_width, wnd->new_height, force);
-       }
-
-       if (wnd->need_redraw) {
+               resize_window(wnd, wnd->new_width, wnd->new_height);
+       } else {
                wnd->need_frame = true;
-               wnd->need_redraw = false;
                wnd->w_frame = wl_surface_frame(wnd->w_surface);
                wl_callback_add_listener(wnd->w_frame,
                                         &frame_callback_listener, wnd);
@@ -1448,6 +1438,8 @@ static void do_frame(struct wlt_window *wnd)
        }
 }
 
+static void schedule_frame(struct wlt_window *wnd);
+
 static void frame_callback(void *data, struct wl_callback *w_callback,
                           uint32_t time)
 {
@@ -1455,9 +1447,10 @@ static void frame_callback(void *data, struct wl_callback *w_callback,
 
        wl_callback_destroy(w_callback);
        wnd->w_frame = NULL;
-       wnd->need_frame = false;
 
-       do_frame(wnd);
+       wnd->idle_pending = false;
+       if (wnd->need_frame)
+               schedule_frame(wnd);
 }
 
 static void idle_frame(struct ev_eloop *eloop, void *unused, void *data)
@@ -1496,10 +1489,12 @@ static void schedule_frame(struct wlt_window *wnd)
 {
        int ret;
 
-       if (!wnd || wnd->w_frame)
+       if (!wnd)
                return;
 
-       if (wnd->need_frame || wnd->idle_pending)
+       wnd->need_frame = true;
+
+       if (wnd->idle_pending)
                return;
 
        ret = ev_eloop_register_idle_cb(wnd->disp->eloop, idle_frame, wnd,
@@ -1592,7 +1587,7 @@ int wlt_display_create_window(struct wlt_display *disp,
                                      &shell_surface_listener, wnd);
        wl_shell_surface_set_toplevel(wnd->w_shell_surface);
 
-       ret = resize_window(wnd, width, height, true);
+       ret = resize_window(wnd, width, height);
        if (ret)
                goto err_shell_surface;
 
@@ -1677,7 +1672,6 @@ void wlt_window_schedule_redraw(struct wlt_window *wnd)
        if (!wnd)
                return;
 
-       wnd->need_redraw = true;
        schedule_frame(wnd);
 }