reworked reparents
authorJavier S. Pedro <maemo@javispedro.com>
Mon, 29 Mar 2010 19:12:52 +0000 (21:12 +0200)
committerJavier S. Pedro <maemo@javispedro.com>
Mon, 29 Mar 2010 19:12:52 +0000 (21:12 +0200)
sdlhaa/debian/changelog
sdlhaa/debian/rules
sdlhaa/src/Makefile
sdlhaa/src/SDL_haa.c
sdlhaa/src/SDL_haa.h
sdlhaa/src/atoms.inc

index 4133431..92068c2 100644 (file)
@@ -1,3 +1,11 @@
+sdlhaa (1.1.0) unstable; urgency=low
+
+  * Added new HAA_SetVideoMode call; removed buggy automatic
+    fullscreen sync.
+  * Fixed Z Rotation.
+
+ -- Javier S. Pedro <maemo@javispedro.com>  Mon, 29 Mar 2010 17:59:06 +0200
+
 sdlhaa (1.0.0) unstable; urgency=low
 
   * Initial Release.
index d97ef58..976f1ab 100755 (executable)
@@ -66,7 +66,7 @@ binary-arch: build install
        dh_strip
        dh_compress
        dh_fixperms
-       dh_makeshlibs -V "libsdl-haa1.2-1 (>= 1.0.0)"
+       dh_makeshlibs -V "libsdl-haa1.2-1 (>= 1.1.0)"
        dh_installdeb
        dh_shlibdeps
        dh_gencontrol
index 055ac9c..308b76a 100644 (file)
@@ -4,7 +4,7 @@ CFLAGS:=-g -O0 -Wall -Wextra
 CC:=gcc
 
 RELEASE:=1.2
-VERSION:=0:1:0
+VERSION:=1:2:1
 
 SDL_HAA_TARGET:=libSDL_haa.la
 
index f77510f..3259884 100644 (file)
@@ -52,12 +52,14 @@ typedef struct HAA_ActorPriv {
        struct HAA_ActorPriv *prev, *next;
 } HAA_ActorPriv;
 
-static Bool initialized = False;
-
 static Display *display;
 static Window parent_window;
 static HAA_ActorPriv *first = NULL, *last = NULL;
 
+/* Queued reparents. */
+static Uint32 queued_reparent_time;
+static Bool queued_reparent_fs;
+
 #ifdef HAVE_XSHM
 static int shm_major, shm_minor;
 static Bool shm_pixmaps;
@@ -77,30 +79,25 @@ int HAA_Init(Uint32 flags)
        }
 
        display = info.info.x11.display;
-       if (flags & SDL_FULLSCREEN) {
-               parent_window = info.info.x11.fswindow;
-       } else {
-               parent_window = info.info.x11.wmwindow;
-       }
+       parent_window = 0;
+       queued_reparent_time = 0;
        first = last = NULL;
 
-       if (!initialized) {
-               XInternAtoms(display, (char**)atom_names, ATOM_COUNT, True, atom_values);
-               initialized = True;
+       XInternAtoms(display, (char**)atom_names, ATOM_COUNT, True, atom_values);
 
 #ifdef HAVE_XSHM
-               have_shm = XShmQueryVersion(display, &shm_major, &shm_minor, &shm_pixmaps);
+       have_shm = XShmQueryVersion(display, &shm_major, &shm_minor, &shm_pixmaps);
 #endif
 
-               SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
-       }
+       /* This might add some noise to your event queue, but we need them. */
+       SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
 
        return 0;
 }
 
 void HAA_Quit()
 {
-       
+       /* Nothing to do for now */
 }
 
 static HAA_ActorPriv* find_actor_for_window(Window w)
@@ -137,57 +134,120 @@ static void actor_send_message(HAA_ActorPriv* actor, Atom message_type,
                (XEvent *)&event);
 }
 
-static void HAA_ReparentAllTo(Window new_parent)
+static void reparent_all_to(Window new_parent)
 {
-       if (new_parent != parent_window) {
-               HAA_ActorPriv* a;
-               /* video mode has changed */
-               parent_window = new_parent;
-
-               /* unmap all actors that were already ready */
-               for (a = first; a; a = a->next) {
-                       a->parent = parent_window;
-                       if (a->ready) {
-                               XUnmapWindow(display, a->window);
-                       }
-               }
+       HAA_ActorPriv* a;
+       /* video mode has changed */
+       parent_window = new_parent;
 
-               XSync(display, False);
+       /* if we don't have any actors, no need to reparent them */
+       if (first == NULL) {
+               assert(last == NULL);
+               return;
+       }
 
-               /* now remap and reconfigure all actors */
-               for (a = first; a; a = a->next) {
-                       if (a->ready) {
-                               XMapWindow(display, a->window);
-                               a->ready = 0;
-                               a->p.pending |= HAA_PENDING_EVERYTHING;
-                       } else {
-                               a->p.pending |= HAA_PENDING_PARENT | HAA_PENDING_SHOW;
-                       }
+       /* unmap all actors that were already ready */
+       for (a = first; a; a = a->next) {
+               a->parent = parent_window;
+               if (a->ready) {
+                       XUnmapWindow(display, a->window);
                }
+       }
+
+       XSync(display, False);
 
-               XFlush(display);
+       /* now remap and reconfigure all actors */
+       for (a = first; a; a = a->next) {
+               if (a->ready) {
+                       XMapWindow(display, a->window);
+                       a->ready = 0;
+                       a->p.pending |= HAA_PENDING_EVERYTHING;
+               } else {
+                       a->p.pending |= HAA_PENDING_PARENT | HAA_PENDING_SHOW;
+               }
        }
+
+       XFlush(display);
 }
 
-static void HAA_AutoReparent()
+static int auto_reparent_all_to(Bool fullscreen)
 {
        SDL_SysWMinfo info;
-       SDL_Surface *screen = SDL_GetVideoSurface();
        Window new_parent;
-
-       if (!screen) return;
+       XWindowAttributes attr;
+       Bool is_mapped;
+       int res;
 
        SDL_VERSION(&info.version);
-       int res = SDL_GetWMInfo(&info);
+       res = SDL_GetWMInfo(&info);
        assert(res == 1);
 
-       if (screen->flags & SDL_FULLSCREEN) {
+       /* Delete any pending reparent */
+       queued_reparent_time = 0;
+
+       if (fullscreen) {
                new_parent = info.info.x11.fswindow;
        } else {
                new_parent = info.info.x11.wmwindow;
        }
-       
-       HAA_ReparentAllTo(new_parent);
+
+       XGetWindowAttributes(display, new_parent, &attr);
+       is_mapped = attr.map_state == IsViewable;
+
+       /* Do we really need to reparent? */
+       if (new_parent != parent_window) {
+               /* Yes, we do. */
+               if (is_mapped) {
+                       reparent_all_to(new_parent);
+                       return 0;
+               } else {
+                       return 1;
+               }
+       } else if (!is_mapped) {
+               /* We don't actually need to reparent,
+                * but we found that our current parent has been unmapped! */
+               parent_window = 0; // Make current one it invalid
+               return 1; // Signal failure
+       } else {
+               /* We don't need to reparent and everything is OK. */
+               return 0;
+       }
+}
+
+static void handle_queued_reparent()
+{
+       if (queued_reparent_time) {
+               /* A reparent is pending. */
+               Uint32 now = SDL_GetTicks();
+               if (now > queued_reparent_time) {
+                       /* Try to do the queued reparent now. */
+                       int res = auto_reparent_all_to(queued_reparent_fs);
+                       if (res != 0) {
+                               /* Failed to reparent? Try again in 200 ms. */
+                               queued_reparent_time = now + 200;
+                       }
+               }
+       }
+}
+
+static void queue_auto_reparent_to(Bool fullscreen, Uint32 delay)
+{
+       queued_reparent_time = SDL_GetTicks() + delay;
+       queued_reparent_fs = fullscreen;
+}
+
+int HAA_SetVideoMode()
+{
+       SDL_Surface *screen = SDL_GetVideoSurface();
+
+       if (!screen) {
+               SDL_SetError("Failed to get current video surface");
+               return 1;
+       }
+
+       auto_reparent_all_to(screen->flags & SDL_FULLSCREEN ? True : False);
+
+       return 0;
 }
 
 static void HAA_Pending(HAA_ActorPriv* actor)
@@ -225,7 +285,7 @@ static void HAA_Pending(HAA_ActorPriv* actor)
                 actor_send_message(actor,
                        ATOM(_HILDON_ANIMATION_CLIENT_MESSAGE_ROTATION),
                        HAA_Z_AXIS,
-                       actor->p.x_rotation_angle,
+                       actor->p.z_rotation_angle,
                        actor->p.z_rotation_x, actor->p.z_rotation_y, 0);
        }
 
@@ -249,6 +309,7 @@ static void HAA_Pending(HAA_ActorPriv* actor)
        actor->p.pending = HAA_PENDING_NOTHING;
 }
 
+/** Push a SDL_VIDEOEXPOSE event to the queue */
 static void sdl_expose()
 {
        SDL_Event events[32];
@@ -265,6 +326,7 @@ static void sdl_expose()
        }
 }
 
+/** Called when the client ready notification is received. */
 static void actor_update_ready(HAA_ActorPriv* actor)
 {
        Window window = actor->window;
@@ -314,12 +376,11 @@ static void actor_update_ready(HAA_ActorPriv* actor)
 
 int HAA_FilterEvent(const SDL_Event *event)
 {
-       switch (event->type) {
+       handle_queued_reparent();
 
-       case SDL_SYSWMEVENT: {
+       if (event->type == SDL_SYSWMEVENT) {
                const XEvent *e = &event->syswm.msg->event.xevent;
-               switch(e->type) {
-               case PropertyNotify:
+               if (e->type == PropertyNotify) {
                        if (e->xproperty.atom == ATOM(_HILDON_ANIMATION_CLIENT_READY)) {
                                HAA_ActorPriv* actor =
                                        find_actor_for_window(e->xproperty.window);
@@ -328,25 +389,37 @@ int HAA_FilterEvent(const SDL_Event *event)
                                        return 0; // Handled
                                }
                        }
-                       break;
                }
-       }
-       break;
-
-       case SDL_KEYUP: {
-               /* For reasons unknown, we seem to receive this on fullscreen events */
-               const SDL_keysym *key = &event->key.keysym;
-               if (key->scancode == 0 && key->sym == SDLK_NUMLOCK &&
-                               key->mod == KMOD_NUM) {
-                       /* Either task switched or fullscreen invoked */
-                       HAA_AutoReparent();
+       } else if (event->type == SDL_ACTIVEEVENT) {
+               /* We know that after an input focus loss, the fullscreen window
+                * will be unampped. We get no warnings about when this happens.
+                * So we take a preventive approach and automatically reparent to the
+                * windowed window when any out of focus event happens.
+                * Of course, we have then to reparent to the fullscreen window when
+                * the focus comes back. But we have a problem: there's a 1.5 second
+                * delay between getting focus and SDL actually mapping the fullscreen
+                * window, and we cannot reparent back to the fullscreen window while
+                * it is unmapped.
+                */
+               if (event->active.state == SDL_APPINPUTFOCUS) {
+                       SDL_Surface *screen = SDL_GetVideoSurface();
+                       if (screen && screen->flags & SDL_FULLSCREEN) {
+                               if (event->active.gain) {
+                                       /* Gaining fullscreen focus:
+                                        * Wait for 1.5 seconds before reparenting to fullscreen.
+                                        */
+                                       queue_auto_reparent_to(True, 1500);
+                               } else {
+                                       /* Losing fullscreen focus:
+                                        * Windowed mode window is always mapped; can reparent now.
+                                        */
+                                       auto_reparent_all_to(False);
+                               }
+                       }
                }
        }
-       break;
-
-       }
 
-       return 1;
+       return 1; // Unhandled event
 }
 
 HAA_Actor* HAA_CreateActor(Uint32 flags,
@@ -358,6 +431,13 @@ HAA_Actor* HAA_CreateActor(Uint32 flags,
                return NULL;
        }
 
+       /* Refresh the parent_window if needed. */
+       int res = HAA_SetVideoMode();
+       if (res != 0) {
+               goto cleanup_actor;
+               return NULL;
+       }
+
        /* Default actor settings */
        actor->p.position_x = 0;
        actor->p.position_y = 0;
@@ -488,13 +568,13 @@ HAA_Actor* HAA_CreateActor(Uint32 flags,
                        goto cleanup_window;
                }
        }
-       
+
        /* Guess alpha mask */
        Uint32 Amask = 0;
        if (image->depth == 32) {
                Amask = ~(vinfo.red_mask | vinfo.green_mask | vinfo.blue_mask);
        }
-       
+
        /* Create GC */
        GC gc = actor->gc = XCreateGC(display, window, 0, NULL);
        XSetForeground(display, gc, 0xFFFFFFFFU);
@@ -566,6 +646,7 @@ void HAA_FreeActor(HAA_Actor* a)
                XFreeColormap(display, actor->colormap);
        SDL_FreeSurface(actor->p.surface);
 
+       /* Remove actor from global linked list */
        if (first == actor && last == actor) {
                assert(!actor->next && !actor->prev);
                first = NULL;
index 6549a20..db9c5d2 100644 (file)
@@ -73,7 +73,7 @@ typedef struct HAA_Actor {
 } HAA_Actor;
 
 /** Invoke after SDL_Init.
-       @param flags SDL_FULLSCREEN if you will set a fullscreen video mode.
+       @param flags reserved for future expansion (pass 0)
        @return 0 if SDL_haa was initialized correctly.
   */
 extern DECLSPEC int SDLCALL HAA_Init(Uint32 flags);
@@ -89,6 +89,20 @@ extern DECLSPEC void SDLCALL HAA_Quit();
 */
 extern DECLSPEC int SDLCALL HAA_FilterEvent(const SDL_Event *event);
 
+/** Call after calling SDL_SetVideoMode() if you have any actors created
+  * to ensure they're visible in the new window.
+  * @return 0 if everything went OK.
+  */
+extern DECLSPEC int SDLCALL HAA_SetVideoMode(void);
+
+/** Creates both an animation actor and its associated surface.
+  * @param flags reserved (pass 0)
+  * @param width size of the actor surface
+  * @param height
+  * @param bitsPerPixel depth of the actor surface
+  *    a 32 bpp surface will have an alpha channel.
+  * @return the created HAA_Actor, or NULL if an error happened.
+  */
 extern DECLSPEC HAA_Actor* SDLCALL HAA_CreateActor(Uint32 flags,
        int width, int height, int bitsPerPixel);
 
index 776c61d..88592b3 100644 (file)
 /* Definitions for all the atoms the library is going to use */
 
 enum atoms {
-       ATOM_HILDON_NON_COMPOSITED_WINDOW = 0,
-       ATOM_HILDON_STACKABLE_WINDOW,
        ATOM_NET_WM_STATE,
        ATOM_NET_WM_STATE_FULLSCREEN,
        ATOM_NET_WM_WINDOW_TYPE,
-       ATOM_NET_WM_WINDOW_TYPE_NORMAL,
-       ATOM_NET_WM_WINDOW_TYPE_DIALOG,
        ATOM_HILDON_WM_WINDOW_TYPE_ANIMATION_ACTOR,
        ATOM_HILDON_ANIMATION_CLIENT_READY,
        ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_SHOW,
@@ -39,13 +35,9 @@ enum atoms {
 };
 
 static const char * atom_names[] = {
-       "_HILDON_NON_COMPOSITED_WINDOW",
-       "_HILDON_STACKABLE_WINDOW",
        "_NET_WM_STATE",
        "_NET_WM_STATE_FULLSCREEN",
        "_NET_WM_WINDOW_TYPE",
-       "_NET_WM_WINDOW_TYPE_NORMAL",
-       "_NET_WM_WINDOW_TYPE_DIALOG",
        "_HILDON_WM_WINDOW_TYPE_ANIMATION_ACTOR",
        "_HILDON_ANIMATION_CLIENT_READY",
        "_HILDON_ANIMATION_CLIENT_MESSAGE_SHOW",