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;
}
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)
(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)
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);
}
actor->p.pending = HAA_PENDING_NOTHING;
}
+/** Push a SDL_VIDEOEXPOSE event to the queue */
static void sdl_expose()
{
SDL_Event events[32];
}
}
+/** Called when the client ready notification is received. */
static void actor_update_ready(HAA_ActorPriv* actor)
{
Window window = actor->window;
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);
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,
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;
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);
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;