[Cogl] [PATCH] onscreen: Adds support for resizeable windows
Robert Bragg
robert at sixbynine.org
Wed Jun 20 11:23:28 PDT 2012
From: Robert Bragg <robert at linux.intel.com>
This adds api to be able to request that the window system allows a
given onscreen framebuffer to be resizeable, and api to add and remove
resize handlers to be called whenever the framebuffer does actually
change size.
The new functions are:
cogl_onscreen_{get,set}_resizeable()
cogl_onscreen_{add,remove}_resize_handler()
The examples cogl-hello and cogl-x11-foreign have been updated to use
the new api. To smoke test how Cogl updates the viewport automatically
in response to window resizes the cogl-hello test doesn't explicitly
respond to resize events by setting the viewport and cogl-x11-foreign
responds by setting a viewport that is offset by a quarter of the
window's width/height and half the width and height of the window.
---
cogl/cogl-glx-display-private.h | 1 +
cogl/cogl-onscreen-private.h | 19 +++++
cogl/cogl-onscreen.c | 99 ++++++++++++++++++++++-
cogl/cogl-onscreen.h | 138 +++++++++++++++++++++++++++++++++
cogl/cogl-sdl.c | 2 +
cogl/winsys/cogl-winsys-egl-private.h | 4 +
cogl/winsys/cogl-winsys-egl-x11.c | 118 +++++++++++++++++++++++++---
cogl/winsys/cogl-winsys-glx.c | 99 ++++++++++++++++++++----
cogl/winsys/cogl-winsys-private.h | 3 +
cogl/winsys/cogl-winsys-sdl.c | 92 +++++++++++++++++++++-
examples/cogl-hello.c | 2 +
examples/cogl-x11-foreign.c | 24 +++++-
12 files changed, 563 insertions(+), 38 deletions(-)
diff --git a/cogl/cogl-glx-display-private.h b/cogl/cogl-glx-display-private.h
index f5d4e05..1ffcd32 100644
--- a/cogl/cogl-glx-display-private.h
+++ b/cogl/cogl-glx-display-private.h
@@ -51,6 +51,7 @@ typedef struct _CoglGLXDisplay
GLXWindow dummy_glxwin;
Window dummy_xwin;
CoglBool pending_swap_notify;
+ CoglBool pending_resize_notify;
} CoglGLXDisplay;
#endif /* __COGL_DISPLAY_GLX_PRIVATE_H */
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
index 08774db..f8de1a7 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl-onscreen-private.h
@@ -46,6 +46,19 @@ struct _CoglSwapBuffersNotifyEntry
unsigned int id;
};
+typedef struct _CoglResizeNotifyEntry CoglResizeNotifyEntry;
+
+COGL_TAILQ_HEAD (CoglResizeNotifyList, CoglResizeNotifyEntry);
+
+struct _CoglResizeNotifyEntry
+{
+ COGL_TAILQ_ENTRY (CoglResizeNotifyEntry) list_node;
+
+ CoglOnscreenResizeCallback callback;
+ void *user_data;
+ unsigned int id;
+};
+
struct _CoglOnscreen
{
CoglFramebuffer _parent;
@@ -64,6 +77,9 @@ struct _CoglOnscreen
CoglSwapBuffersNotifyList swap_callbacks;
+ CoglBool resizeable;
+ CoglResizeNotifyList resize_callbacks;
+
void *winsys;
};
@@ -77,4 +93,7 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
void
_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen);
+void
+_cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
+
#endif /* __COGL_ONSCREEN_PRIVATE_H */
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
index 242754c..dda7d4c 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl-onscreen.c
@@ -46,6 +46,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
COGL_TAILQ_INIT (&onscreen->swap_callbacks);
+ COGL_TAILQ_INIT (&onscreen->resize_callbacks);
framebuffer->config = onscreen_template->config;
cogl_object_ref (framebuffer->config.swap_chain);
@@ -113,6 +114,13 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
+ CoglResizeNotifyEntry *resize_entry;
+
+ while ((resize_entry = COGL_TAILQ_FIRST (&onscreen->resize_callbacks)))
+ {
+ COGL_TAILQ_REMOVE (&onscreen->resize_callbacks, resize_entry, list_node);
+ g_slice_free (CoglResizeNotifyEntry, resize_entry);
+ }
if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen))
framebuffer->context->window_buffer = NULL;
@@ -347,6 +355,22 @@ _cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
}
void
+_cogl_onscreen_notify_resize (CoglOnscreen *onscreen)
+{
+ CoglResizeNotifyEntry *entry, *tmp;
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+
+ COGL_TAILQ_FOREACH_SAFE (entry,
+ &onscreen->resize_callbacks,
+ list_node,
+ tmp)
+ entry->callback (onscreen,
+ framebuffer->width,
+ framebuffer->height,
+ entry->user_data);
+}
+
+void
_cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
int width, int height)
{
@@ -356,11 +380,78 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
framebuffer->width = width;
framebuffer->height = height;
- /* The framebuffer geometry can affect the GL viewport so if the
- * framebuffer being updated is the current framebuffer we mark the
- * viewport state as changed so it will be updated the next time
- * _cogl_framebuffer_flush_state() is called. */
+ framebuffer->viewport_x = 0;
+ framebuffer->viewport_y = 0;
+ framebuffer->viewport_width = width;
+ framebuffer->viewport_height = height;
+
+ /* If the framebuffer being updated is the current framebuffer we
+ * mark the viewport state as changed so it will be updated the next
+ * time _cogl_framebuffer_flush_state() is called. */
if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |=
COGL_FRAMEBUFFER_STATE_VIEWPORT;
}
+
+void
+cogl_onscreen_set_resizeable (CoglOnscreen *onscreen,
+ CoglBool resizeable)
+{
+ CoglFramebuffer *framebuffer;
+ const CoglWinsysVtable *winsys;
+
+ if (onscreen->resizeable == resizeable)
+ return;
+
+ onscreen->resizeable = resizeable;
+
+ framebuffer = COGL_FRAMEBUFFER (onscreen);
+ if (framebuffer->allocated)
+ {
+ winsys = _cogl_framebuffer_get_winsys (COGL_FRAMEBUFFER (onscreen));
+
+ if (winsys->onscreen_set_resizeable)
+ winsys->onscreen_set_resizeable (onscreen, resizeable);
+ }
+}
+
+CoglBool
+cogl_onscreen_get_resizeable (CoglOnscreen *onscreen)
+{
+ return onscreen->resizeable;
+}
+
+unsigned int
+cogl_onscreen_add_resize_handler (CoglOnscreen *onscreen,
+ CoglOnscreenResizeCallback callback,
+ void *user_data)
+{
+ CoglResizeNotifyEntry *entry = g_slice_new (CoglResizeNotifyEntry);
+ static int next_resize_callback_id = 0;
+
+ entry->callback = callback;
+ entry->user_data = user_data;
+ entry->id = next_resize_callback_id++;
+
+ COGL_TAILQ_INSERT_TAIL (&onscreen->resize_callbacks, entry, list_node);
+
+ return entry->id;
+}
+
+void
+cogl_onscreen_remove_resize_handler (CoglOnscreen *onscreen,
+ unsigned int id)
+{
+ CoglResizeNotifyEntry *entry;
+
+ COGL_TAILQ_FOREACH (entry, &onscreen->resize_callbacks, list_node)
+ {
+ if (entry->id == id)
+ {
+ COGL_TAILQ_REMOVE (&onscreen->resize_callbacks, entry, list_node);
+ g_slice_free (CoglResizeNotifyEntry, entry);
+ break;
+ }
+ }
+}
+
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index 339bdf3..ed0eb12 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl-onscreen.h
@@ -381,6 +381,144 @@ cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
unsigned int id);
/**
+ * cogl_onscreen_set_resizeable:
+ * @onscreen: A #CoglOnscreen framebuffer
+ *
+ * Lets you request Cogl to mark an @onscreen framebuffer as
+ * resizeable or not.
+ *
+ * By default, if possible, a @onscreen will be created by Cogl
+ * as non resizeable, but it is not guaranteed that this is always
+ * possible for all window systems.
+ *
+ * <note>Cogl does not know whether marking the @onscreen framebuffer
+ * is truly meaningful for your current window system (consider
+ * applications being run fullscreen on a phone or TV) so this
+ * function may not have any useful effect. If you are running on a
+ * multi windowing system such as X11 or Win32 or OSX then Cogl will
+ * request to the window system that users be allowed to resize the
+ * @onscreen, although it's still possible that some other window
+ * management policy will block this possibility.</note>
+ *
+ * <note>Whenever an @onscreen framebuffer is resized the viewport
+ * will be automatically updated to match the new size of the
+ * framebuffer with an origin of (0,0). If your application needs more
+ * specialized control of the viewport it will need to register a
+ * resize handler using cogl_onscreen_add_resize_handler() so that it
+ * can track when the viewport has been changed automatically.</note>
+ *
+ * Since: 2.0
+ */
+void
+cogl_onscreen_set_resizeable (CoglOnscreen *onscreen,
+ CoglBool resizeable);
+
+/**
+ * cogl_onscreen_get_resizeable:
+ * @onscreen: A #CoglOnscreen framebuffer
+ *
+ * Lets you query whether @onscreen has been marked as resizeable via
+ * the cogl_onscreen_set_resizeable() api.
+ *
+ * By default, if possible, a @onscreen will be created by Cogl
+ * as non resizeable, but it is not guaranteed that this is always
+ * possible for all window systems.
+ *
+ * <note>If cogl_onscreen_set_resizeable(@onscreen, %TRUE) has been
+ * previously called then this function will return %TRUE, but it's
+ * possible that the current windowing system being used does not
+ * support window resizing (consider fullscreen windows on a phone or
+ * a TV). This function is not aware of whether resizing is truly
+ * meaningful with your window system, only whether the @onscreen has
+ * been marked as resizeable.</note>
+ *
+ * Return value: Returns whether @onscreen has been marked as
+ * resizeable or not.
+ * Since: 2.0
+ */
+CoglBool
+cogl_onscreen_get_resizeable (CoglOnscreen *onscreen);
+
+/**
+ * CoglOnscreenResizeCallback:
+ * @onscreen: A #CoglOnscreen framebuffer that was resized
+ * @width: The new width of @onscreen
+ * @height: The new height of @onscreen
+ * @user_data: The private passed to
+ * cogl_onscreen_add_resize_handler()
+ *
+ * Is a callback type used with the
+ * cogl_onscreen_add_resize_handler() allowing applications to be
+ * notified whenever an @onscreen framebuffer is resized.
+ *
+ * <note>Cogl automatically updates the viewport of an @onscreen
+ * framebuffer that is resized so this callback is also an indication
+ * that the viewport has been modified too</note>
+ *
+ * <note>A resize callback will only ever be called while dispatching
+ * Cogl events from the system mainloop; so for example during
+ * cogl_poll_dispatch(). This is so that callbacks shouldn't occur
+ * while an application might have arbitrary locks held for
+ * example.</note>
+ *
+ * Since: 2.0
+ */
+typedef void (*CoglOnscreenResizeCallback) (CoglOnscreen *onscreen,
+ int width,
+ int height,
+ void *user_data);
+
+/**
+ * cogl_onscreen_add_resize_handler:
+ * @onscreen: A #CoglOnscreen framebuffer
+ * @callback: A #CoglOnscreenResizeCallback to call when the @onscreen
+ * changes size.
+ * @user_data: Private data to be passed to @callback.
+ *
+ * Registers a @callback with @onscreen that will be called whenever
+ * the @onscreen framebuffer changes size.
+ *
+ * The @callback can be removed using
+ * cogl_onscreen_remove_resize_handler() passing the same @callback
+ * and @user_data pair.
+ *
+ * <note>Since Cogl automatically updates the viewport of an @onscreen
+ * framebuffer that is resized, a resize callback can also be used to
+ * track when the viewport has been changed automatically by Cogl in
+ * case your application needs more specialized control over the
+ * viewport.</note>
+ *
+ * <note>A resize callback will only ever be called while dispatching
+ * Cogl events from the system mainloop; so for example during
+ * cogl_poll_dispatch(). This is so that callbacks shouldn't occur
+ * while an application might have arbitrary locks held for
+ * example.</note>
+ *
+ * Return value: a unique identifier that can be used to remove to remove
+ * the callback later.
+ *
+ * Since: 2.0
+ */
+unsigned int
+cogl_onscreen_add_resize_handler (CoglOnscreen *onscreen,
+ CoglOnscreenResizeCallback callback,
+ void *user_data);
+
+/**
+ * cogl_onscreen_remove_resize_handler:
+ * @onscreen: A #CoglOnscreen framebuffer
+ * @id: An identifier returned from cogl_onscreen_add_resize_handler()
+ *
+ * Removes a resize @callback and @user_data pair that were previously
+ * associated with @onscreen via cogl_onscreen_add_resize_handler().
+ *
+ * Since: 2.0
+ */
+void
+cogl_onscreen_remove_resize_handler (CoglOnscreen *onscreen,
+ unsigned int id);
+
+/**
* cogl_is_onscreen:
* @object: A #CoglObject pointer
*
diff --git a/cogl/cogl-sdl.c b/cogl/cogl-sdl.c
index 5de1683..c4adbf8 100644
--- a/cogl/cogl-sdl.c
+++ b/cogl/cogl-sdl.c
@@ -74,6 +74,8 @@ cogl_sdl_handle_event (CoglContext *context, SDL_Event *event)
winsys = _cogl_context_get_winsys (context);
+ _cogl_renderer_handle_native_event (context->display->renderer, event);
+
if (winsys->poll_dispatch)
winsys->poll_dispatch (context, NULL, 0);
}
diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/winsys/cogl-winsys-egl-private.h
index c03bf15..96e7a7f 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/winsys/cogl-winsys-egl-private.h
@@ -119,6 +119,8 @@ typedef struct _CoglDisplayEGL
EGLSurface current_draw_surface;
EGLContext current_context;
+ CoglBool pending_resize_notify;
+
/* Platform specific display data */
void *platform;
} CoglDisplayEGL;
@@ -133,6 +135,8 @@ typedef struct _CoglOnscreenEGL
{
EGLSurface egl_surface;
+ CoglBool pending_resize_notify;
+
/* Platform specific data */
void *platform;
} CoglOnscreenEGL;
diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c
index 94a9410..12604b0 100644
--- a/cogl/winsys/cogl-winsys-egl-x11.c
+++ b/cogl/winsys/cogl-winsys-egl-x11.c
@@ -89,6 +89,32 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
return NULL;
}
+static void
+notify_resize (CoglContext *context,
+ GLXDrawable drawable,
+ int width,
+ int height)
+{
+ CoglOnscreen *onscreen = find_onscreen_for_xid (context, drawable);
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglDisplay *display = context->display;
+ CoglDisplayEGL *egl_display = display->winsys;
+ CoglOnscreenEGL *egl_onscreen;
+
+ if (!onscreen)
+ return;
+
+ egl_onscreen = onscreen->winsys;
+
+ _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
+
+ /* We only want to notify that a resize happened when the
+ application calls cogl_context_dispatch so instead of immediately
+ notifying we'll set a flag to remember to notify later */
+ egl_display->pending_resize_notify = TRUE;
+ egl_onscreen->pending_resize_notify = TRUE;
+}
+
static CoglFilterReturn
event_filter_cb (XEvent *xevent, void *data)
{
@@ -96,17 +122,10 @@ event_filter_cb (XEvent *xevent, void *data)
if (xevent->type == ConfigureNotify)
{
- CoglOnscreen *onscreen =
- find_onscreen_for_xid (context, xevent->xconfigure.window);
-
- if (onscreen)
- {
- CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-
- _cogl_framebuffer_winsys_update_size (framebuffer,
- xevent->xconfigure.width,
- xevent->xconfigure.height);
- }
+ notify_resize (context,
+ xevent->xconfigure.window,
+ xevent->xconfigure.width,
+ xevent->xconfigure.height);
}
return COGL_FILTER_CONTINUE;
@@ -441,6 +460,45 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin);
}
+static void
+_cogl_winsys_onscreen_set_resizeable (CoglOnscreen *onscreen,
+ CoglBool resizeable)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglXlibRenderer *xlib_renderer =
+ _cogl_xlib_renderer_get_data (context->display->renderer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglOnscreenXlib *xlib_onscreen = egl_onscreen->platform;
+
+ XSizeHints *size_hints = XAllocSizeHints ();
+
+ if (resizeable)
+ {
+ /* TODO: Add cogl_onscreen_request_minimum_size () */
+ size_hints->min_width = 1;
+ size_hints->min_height = 1;
+
+ size_hints->max_width = INT_MAX;
+ size_hints->max_height = INT_MAX;
+ }
+ else
+ {
+ int width = cogl_framebuffer_get_width (framebuffer);
+ int height = cogl_framebuffer_get_height (framebuffer);
+
+ size_hints->min_width = width;
+ size_hints->min_height = height;
+
+ size_hints->max_width = width;
+ size_hints->max_height = height;
+ }
+
+ XSetWMNormalHints (xlib_renderer->xdpy, xlib_onscreen->xwin, size_hints);
+
+ XFree (size_hints);
+}
+
static uint32_t
_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
{
@@ -570,10 +628,35 @@ _cogl_winsys_poll_get_info (CoglContext *context,
int *n_poll_fds,
int64_t *timeout)
{
+ CoglDisplay *display = context->display;
+ CoglDisplayEGL *egl_display = display->winsys;
+
_cogl_xlib_renderer_poll_get_info (context->display->renderer,
poll_fds,
n_poll_fds,
timeout);
+
+ if (egl_display->pending_resize_notify)
+ *timeout = 0;
+}
+
+static void
+flush_pending_notifications_cb (void *data,
+ void *user_data)
+{
+ CoglFramebuffer *framebuffer = data;
+
+ if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+ {
+ CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+
+ if (egl_onscreen->pending_resize_notify)
+ {
+ _cogl_onscreen_notify_resize (onscreen);
+ egl_onscreen->pending_resize_notify = FALSE;
+ }
+ }
}
static void
@@ -581,9 +664,20 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
const CoglPollFD *poll_fds,
int n_poll_fds)
{
+ CoglDisplay *display = context->display;
+ CoglDisplayEGL *egl_display = display->winsys;
+
_cogl_xlib_renderer_poll_dispatch (context->display->renderer,
poll_fds,
n_poll_fds);
+
+ if (egl_display->pending_resize_notify)
+ {
+ g_list_foreach (context->framebuffers,
+ flush_pending_notifications_cb,
+ NULL);
+ egl_display->pending_resize_notify = FALSE;
+ }
}
#ifdef EGL_KHR_image_pixmap
@@ -726,6 +820,8 @@ _cogl_winsys_egl_xlib_get_vtable (void)
vtable.onscreen_set_visibility =
_cogl_winsys_onscreen_set_visibility;
+ vtable.onscreen_set_resizeable =
+ _cogl_winsys_onscreen_set_resizeable;
vtable.onscreen_x11_get_window_xid =
_cogl_winsys_onscreen_x11_get_window_xid;
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 6650106..e6dea0b 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -80,6 +80,7 @@ typedef struct _CoglOnscreenGLX
GLXDrawable glxwin;
uint32_t last_swap_vsync_counter;
CoglBool pending_swap_notify;
+ CoglBool pending_resize_notify;
} CoglOnscreenGLX;
typedef struct _CoglTexturePixmapGLX
@@ -178,6 +179,32 @@ notify_swap_buffers (CoglContext *context, GLXDrawable drawable)
glx_onscreen->pending_swap_notify = TRUE;
}
+static void
+notify_resize (CoglContext *context,
+ GLXDrawable drawable,
+ int width,
+ int height)
+{
+ CoglOnscreen *onscreen = find_onscreen_for_xid (context, drawable);
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglDisplay *display = context->display;
+ CoglGLXDisplay *glx_display = display->winsys;
+ CoglOnscreenGLX *glx_onscreen;
+
+ if (!onscreen)
+ return;
+
+ glx_onscreen = onscreen->winsys;
+
+ _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
+
+ /* We only want to notify that a resize happened when the
+ application calls cogl_context_dispatch so instead of immediately
+ notifying we'll set a flag to remember to notify later */
+ glx_display->pending_resize_notify = TRUE;
+ glx_onscreen->pending_resize_notify = TRUE;
+}
+
static CoglFilterReturn
glx_event_filter_cb (XEvent *xevent, void *data)
{
@@ -188,17 +215,10 @@ glx_event_filter_cb (XEvent *xevent, void *data)
if (xevent->type == ConfigureNotify)
{
- CoglOnscreen *onscreen =
- find_onscreen_for_xid (context, xevent->xconfigure.window);
-
- if (onscreen)
- {
- CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-
- _cogl_framebuffer_winsys_update_size (framebuffer,
- xevent->xconfigure.width,
- xevent->xconfigure.height);
- }
+ notify_resize (context,
+ xevent->xconfigure.window,
+ xevent->xconfigure.width,
+ xevent->xconfigure.height);
/* we let ConfigureNotify pass through */
return COGL_FILTER_CONTINUE;
@@ -1407,6 +1427,44 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin);
}
+static void
+_cogl_winsys_onscreen_set_resizeable (CoglOnscreen *onscreen,
+ CoglBool resizeable)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglXlibRenderer *xlib_renderer =
+ _cogl_xlib_renderer_get_data (context->display->renderer);
+ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys;
+
+ XSizeHints *size_hints = XAllocSizeHints ();
+
+ if (resizeable)
+ {
+ /* TODO: Add cogl_onscreen_request_minimum_size () */
+ size_hints->min_width = 1;
+ size_hints->min_height = 1;
+
+ size_hints->max_width = INT_MAX;
+ size_hints->max_height = INT_MAX;
+ }
+ else
+ {
+ int width = cogl_framebuffer_get_width (framebuffer);
+ int height = cogl_framebuffer_get_height (framebuffer);
+
+ size_hints->min_width = width;
+ size_hints->min_height = height;
+
+ size_hints->max_width = width;
+ size_hints->max_height = height;
+ }
+
+ XSetWMNormalHints (xlib_renderer->xdpy, xlib_onscreen->xwin, size_hints);
+
+ XFree (size_hints);
+}
+
/* XXX: This is a particularly hacky _cogl_winsys interface... */
static XVisualInfo *
_cogl_winsys_xlib_get_visual_info (void)
@@ -1999,13 +2057,13 @@ _cogl_winsys_poll_get_info (CoglContext *context,
/* If we've already got a pending swap notify then we'll dispatch
immediately */
- if (glx_display->pending_swap_notify)
+ if (glx_display->pending_swap_notify || glx_display->pending_resize_notify)
*timeout = 0;
}
static void
-flush_pending_swap_notify_cb (void *data,
- void *user_data)
+flush_pending_notifications_cb (void *data,
+ void *user_data)
{
CoglFramebuffer *framebuffer = data;
@@ -2019,6 +2077,12 @@ flush_pending_swap_notify_cb (void *data,
_cogl_onscreen_notify_swap_buffers (onscreen);
glx_onscreen->pending_swap_notify = FALSE;
}
+
+ if (glx_onscreen->pending_resize_notify)
+ {
+ _cogl_onscreen_notify_resize (onscreen);
+ glx_onscreen->pending_resize_notify = FALSE;
+ }
}
}
@@ -2034,12 +2098,13 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
poll_fds,
n_poll_fds);
- if (glx_display->pending_swap_notify)
+ if (glx_display->pending_swap_notify || glx_display->pending_resize_notify)
{
g_list_foreach (context->framebuffers,
- flush_pending_swap_notify_cb,
+ flush_pending_notifications_cb,
NULL);
glx_display->pending_swap_notify = FALSE;
+ glx_display->pending_resize_notify = FALSE;
}
}
@@ -2068,6 +2133,8 @@ static CoglWinsysVtable _cogl_winsys_vtable =
.onscreen_x11_get_window_xid =
_cogl_winsys_onscreen_x11_get_window_xid,
.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility,
+ .onscreen_set_resizeable =
+ _cogl_winsys_onscreen_set_resizeable,
.poll_get_info = _cogl_winsys_poll_get_info,
.poll_dispatch = _cogl_winsys_poll_dispatch,
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index cd9ca2e..e549c07 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -119,6 +119,9 @@ typedef struct _CoglWinsysVtable
const int *rectangles,
int n_rectangles);
+ void
+ (*onscreen_set_resizeable) (CoglOnscreen *onscreen, CoglBool resizeable);
+
#ifdef COGL_HAS_EGL_SUPPORT
EGLDisplay
(*context_egl_get_egl_display) (CoglContext *context);
diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
index 58c177a..ee01d50 100644
--- a/cogl/winsys/cogl-winsys-sdl.c
+++ b/cogl/winsys/cogl-winsys-sdl.c
@@ -46,8 +46,9 @@ typedef struct _CoglRendererSdl
typedef struct _CoglDisplaySdl
{
SDL_Surface *surface;
- CoglBool has_onscreen;
+ CoglOnscreen *onscreen;
Uint32 video_mode_flags;
+ CoglBool pending_resize_notify;
} CoglDisplaySdl;
static CoglFuncPtr
@@ -190,6 +191,39 @@ error:
return FALSE;
}
+static CoglFilterReturn
+sdl_event_filter_cb (SDL_Event *event, void *data)
+{
+ if (event->type == SDL_VIDEORESIZE)
+ {
+ CoglContext *context = data;
+ CoglDisplay *display = context->display;
+ CoglDisplaySdl *sdl_display = display->winsys;
+ float width = event->resize.w;
+ float height = event->resize.h;
+ CoglFramebuffer *framebuffer;
+
+ if (!sdl_display->onscreen)
+ return COGL_FILTER_CONTINUE;
+
+ sdl_display->surface = SDL_SetVideoMode (width, height,
+ 0, /* bitsperpixel */
+ sdl_display->video_mode_flags);
+
+ framebuffer = COGL_FRAMEBUFFER (sdl_display->onscreen);
+ _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
+
+ /* We only want to notify that a resize happened when the
+ application calls cogl_context_dispatch so instead of immediately
+ notifying we'll set a flag to remember to notify later */
+ sdl_display->pending_resize_notify = TRUE;
+
+ return COGL_FILTER_CONTINUE;
+ }
+
+ return COGL_FILTER_CONTINUE;
+}
+
static CoglBool
_cogl_winsys_context_init (CoglContext *context, GError **error)
{
@@ -199,6 +233,10 @@ _cogl_winsys_context_init (CoglContext *context, GError **error)
g_error ("cogl_sdl_renderer_set_event_type() or cogl_sdl_context_new() "
"must be called during initialization");
+ _cogl_renderer_add_native_filter (renderer,
+ (CoglNativeFilterFunc)sdl_event_filter_cb,
+ context);
+
return _cogl_context_update_features (context, error);
}
@@ -219,7 +257,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
CoglDisplay *display = context->display;
CoglDisplaySdl *sdl_display = display->winsys;
- sdl_display->has_onscreen = FALSE;
+ sdl_display->onscreen = NULL;
}
static CoglBool
@@ -232,7 +270,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
CoglDisplaySdl *sdl_display = display->winsys;
int width, height;
- if (sdl_display->has_onscreen)
+ if (sdl_display->onscreen)
{
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
@@ -265,7 +303,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
sdl_display->surface->w,
sdl_display->surface->h);
- sdl_display->has_onscreen = TRUE;
+ sdl_display->onscreen = onscreen;
return TRUE;
}
@@ -289,6 +327,49 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
/* SDL doesn't appear to provide a way to set this */
}
+static void
+_cogl_winsys_onscreen_set_resizeable (CoglOnscreen *onscreen,
+ CoglBool resizeable)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+ CoglContext *context = framebuffer->context;
+ CoglDisplay *display = context->display;
+ CoglDisplaySdl *sdl_display = display->winsys;
+ int width, height;
+
+ width = cogl_framebuffer_get_width (framebuffer);
+ height = cogl_framebuffer_get_height (framebuffer);
+
+ if (resizeable)
+ sdl_display->video_mode_flags |= SDL_RESIZABLE;
+ else
+ sdl_display->video_mode_flags &= ~SDL_RESIZABLE;
+
+ sdl_display->surface = SDL_SetVideoMode (width, height,
+ 0, /* bitsperpixel */
+ sdl_display->video_mode_flags);
+}
+
+static void
+_cogl_winsys_poll_dispatch (CoglContext *context,
+ const CoglPollFD *poll_fds,
+ int n_poll_fds)
+{
+ CoglDisplay *display = context->display;
+ CoglDisplaySdl *sdl_display = display->winsys;
+
+ if (sdl_display->pending_resize_notify)
+ {
+ CoglOnscreen *onscreen = sdl_display->onscreen;
+
+ g_return_if_fail (onscreen != NULL);
+
+ _cogl_onscreen_notify_resize (onscreen);
+
+ sdl_display->pending_resize_notify = FALSE;
+ }
+}
+
const CoglWinsysVtable *
_cogl_winsys_sdl_get_vtable (void)
{
@@ -320,6 +401,9 @@ _cogl_winsys_sdl_get_vtable (void)
vtable.onscreen_update_swap_throttled =
_cogl_winsys_onscreen_update_swap_throttled;
vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility;
+ vtable.onscreen_set_resizeable = _cogl_winsys_onscreen_set_resizeable;
+
+ vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE;
}
diff --git a/examples/cogl-hello.c b/examples/cogl-hello.c
index a0b002d..27f562c 100644
--- a/examples/cogl-hello.c
+++ b/examples/cogl-hello.c
@@ -59,6 +59,8 @@ main (int argc, char **argv)
cogl_onscreen_show (onscreen);
data.fb = COGL_FRAMEBUFFER (onscreen);
+ cogl_onscreen_set_resizeable (onscreen, TRUE);
+
data.triangle = cogl_primitive_new_p2c4 (data.ctx,
COGL_VERTICES_MODE_TRIANGLES,
3, triangle_vertices);
diff --git a/examples/cogl-x11-foreign.c b/examples/cogl-x11-foreign.c
index 70049f2..7254857 100644
--- a/examples/cogl-x11-foreign.c
+++ b/examples/cogl-x11-foreign.c
@@ -31,6 +31,16 @@ update_cogl_x11_event_mask (CoglOnscreen *onscreen,
&attrs);
}
+static void
+resize_handler (CoglOnscreen *onscreen,
+ int width,
+ int height,
+ void *user_data)
+{
+ CoglFramebuffer *fb = user_data;
+ cogl_framebuffer_set_viewport (fb, width / 4, height / 4, width / 2, height / 2);
+}
+
int
main (int argc, char **argv)
{
@@ -149,6 +159,9 @@ main (int argc, char **argv)
fb = COGL_FRAMEBUFFER (onscreen);
+ cogl_onscreen_set_resizeable (onscreen, TRUE);
+ cogl_onscreen_add_resize_handler (onscreen, resize_handler, onscreen);
+
triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
3, triangle_vertices);
pipeline = cogl_pipeline_new (ctx);
@@ -170,13 +183,18 @@ main (int argc, char **argv)
}
cogl_xlib_renderer_handle_event (renderer, &event);
}
- cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
- cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
- cogl_onscreen_swap_buffers (onscreen);
+ /* After forwarding native events directly to Cogl you should
+ * then allow Cogl to dispatch any corresponding event
+ * callbacks, such as resize notification callbacks...
+ */
cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
g_poll ((GPollFD *) poll_fds, n_poll_fds, 0);
cogl_poll_dispatch (ctx, poll_fds, n_poll_fds);
+
+ cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+ cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
+ cogl_onscreen_swap_buffers (onscreen);
}
return 0;
--
1.7.7.6
More information about the Cogl
mailing list