onscreen: Adds support for resizable windows

This adds api to be able to request that the window system allows a
given onscreen framebuffer to be resizable, 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}_resizable()
  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.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit a1a8cc00bfa2cecaf1007aec5f3dd95dc07b1786)
This commit is contained in:
Robert Bragg 2012-06-20 16:22:36 +01:00
parent 72f992effe
commit df51574116
12 changed files with 563 additions and 38 deletions

View File

@ -51,6 +51,7 @@ typedef struct _CoglGLXDisplay
GLXWindow dummy_glxwin; GLXWindow dummy_glxwin;
Window dummy_xwin; Window dummy_xwin;
CoglBool pending_swap_notify; CoglBool pending_swap_notify;
CoglBool pending_resize_notify;
} CoglGLXDisplay; } CoglGLXDisplay;
#endif /* __COGL_DISPLAY_GLX_PRIVATE_H */ #endif /* __COGL_DISPLAY_GLX_PRIVATE_H */

View File

@ -46,6 +46,19 @@ struct _CoglSwapBuffersNotifyEntry
unsigned int id; 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 struct _CoglOnscreen
{ {
CoglFramebuffer _parent; CoglFramebuffer _parent;
@ -64,6 +77,9 @@ struct _CoglOnscreen
CoglSwapBuffersNotifyList swap_callbacks; CoglSwapBuffersNotifyList swap_callbacks;
CoglBool resizable;
CoglResizeNotifyList resize_callbacks;
void *winsys; void *winsys;
}; };
@ -77,4 +93,7 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
void void
_cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen); _cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen);
void
_cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
#endif /* __COGL_ONSCREEN_PRIVATE_H */ #endif /* __COGL_ONSCREEN_PRIVATE_H */

View File

@ -46,6 +46,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
COGL_TAILQ_INIT (&onscreen->swap_callbacks); COGL_TAILQ_INIT (&onscreen->swap_callbacks);
COGL_TAILQ_INIT (&onscreen->resize_callbacks);
framebuffer->config = onscreen_template->config; framebuffer->config = onscreen_template->config;
cogl_object_ref (framebuffer->config.swap_chain); cogl_object_ref (framebuffer->config.swap_chain);
@ -113,6 +114,13 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
{ {
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer); 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)) if (framebuffer->context->window_buffer == COGL_FRAMEBUFFER (onscreen))
framebuffer->context->window_buffer = NULL; framebuffer->context->window_buffer = NULL;
@ -346,6 +354,22 @@ _cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
entry->callback (COGL_FRAMEBUFFER (onscreen), entry->user_data); entry->callback (COGL_FRAMEBUFFER (onscreen), entry->user_data);
} }
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 void
_cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer, _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
int width, int height) int width, int height)
@ -356,11 +380,78 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
framebuffer->width = width; framebuffer->width = width;
framebuffer->height = height; framebuffer->height = height;
/* The framebuffer geometry can affect the GL viewport so if the framebuffer->viewport_x = 0;
* framebuffer being updated is the current framebuffer we mark the framebuffer->viewport_y = 0;
* viewport state as changed so it will be updated the next time framebuffer->viewport_width = width;
* _cogl_framebuffer_flush_state() is called. */ 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) if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |= framebuffer->context->current_draw_buffer_changes |=
COGL_FRAMEBUFFER_STATE_VIEWPORT; COGL_FRAMEBUFFER_STATE_VIEWPORT;
} }
void
cogl_onscreen_set_resizable (CoglOnscreen *onscreen,
CoglBool resizable)
{
CoglFramebuffer *framebuffer;
const CoglWinsysVtable *winsys;
if (onscreen->resizable == resizable)
return;
onscreen->resizable = resizable;
framebuffer = COGL_FRAMEBUFFER (onscreen);
if (framebuffer->allocated)
{
winsys = _cogl_framebuffer_get_winsys (COGL_FRAMEBUFFER (onscreen));
if (winsys->onscreen_set_resizable)
winsys->onscreen_set_resizable (onscreen, resizable);
}
}
CoglBool
cogl_onscreen_get_resizable (CoglOnscreen *onscreen)
{
return onscreen->resizable;
}
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;
}
}
}

View File

@ -380,6 +380,144 @@ void
cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen, cogl_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
unsigned int id); unsigned int id);
/**
* cogl_onscreen_set_resizable:
* @onscreen: A #CoglOnscreen framebuffer
*
* Lets you request Cogl to mark an @onscreen framebuffer as
* resizable or not.
*
* By default, if possible, a @onscreen will be created by Cogl
* as non resizable, 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_resizable (CoglOnscreen *onscreen,
CoglBool resizable);
/**
* cogl_onscreen_get_resizable:
* @onscreen: A #CoglOnscreen framebuffer
*
* Lets you query whether @onscreen has been marked as resizable via
* the cogl_onscreen_set_resizable() api.
*
* By default, if possible, a @onscreen will be created by Cogl
* as non resizable, but it is not guaranteed that this is always
* possible for all window systems.
*
* <note>If cogl_onscreen_set_resizable(@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 resizable.</note>
*
* Return value: Returns whether @onscreen has been marked as
* resizable or not.
* Since: 2.0
*/
CoglBool
cogl_onscreen_get_resizable (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: * cogl_is_onscreen:
* @object: A #CoglObject pointer * @object: A #CoglObject pointer

View File

@ -74,6 +74,8 @@ cogl_sdl_handle_event (CoglContext *context, SDL_Event *event)
winsys = _cogl_context_get_winsys (context); winsys = _cogl_context_get_winsys (context);
_cogl_renderer_handle_native_event (context->display->renderer, event);
if (winsys->poll_dispatch) if (winsys->poll_dispatch)
winsys->poll_dispatch (context, NULL, 0); winsys->poll_dispatch (context, NULL, 0);
} }

View File

@ -117,6 +117,8 @@ typedef struct _CoglDisplayEGL
EGLSurface current_draw_surface; EGLSurface current_draw_surface;
EGLContext current_context; EGLContext current_context;
CoglBool pending_resize_notify;
/* Platform specific display data */ /* Platform specific display data */
void *platform; void *platform;
} CoglDisplayEGL; } CoglDisplayEGL;
@ -131,6 +133,8 @@ typedef struct _CoglOnscreenEGL
{ {
EGLSurface egl_surface; EGLSurface egl_surface;
CoglBool pending_resize_notify;
/* Platform specific data */ /* Platform specific data */
void *platform; void *platform;
} CoglOnscreenEGL; } CoglOnscreenEGL;

View File

@ -89,6 +89,32 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
return NULL; 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 static CoglFilterReturn
event_filter_cb (XEvent *xevent, void *data) event_filter_cb (XEvent *xevent, void *data)
{ {
@ -96,17 +122,10 @@ event_filter_cb (XEvent *xevent, void *data)
if (xevent->type == ConfigureNotify) if (xevent->type == ConfigureNotify)
{ {
CoglOnscreen *onscreen = notify_resize (context,
find_onscreen_for_xid (context, xevent->xconfigure.window); xevent->xconfigure.window,
xevent->xconfigure.width,
if (onscreen) xevent->xconfigure.height);
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
_cogl_framebuffer_winsys_update_size (framebuffer,
xevent->xconfigure.width,
xevent->xconfigure.height);
}
} }
return COGL_FILTER_CONTINUE; return COGL_FILTER_CONTINUE;
@ -441,6 +460,45 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin);
} }
static void
_cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen,
CoglBool resizable)
{
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 (resizable)
{
/* 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 static uint32_t
_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen) _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
{ {
@ -570,10 +628,35 @@ _cogl_winsys_poll_get_info (CoglContext *context,
int *n_poll_fds, int *n_poll_fds,
int64_t *timeout) int64_t *timeout)
{ {
CoglDisplay *display = context->display;
CoglDisplayEGL *egl_display = display->winsys;
_cogl_xlib_renderer_poll_get_info (context->display->renderer, _cogl_xlib_renderer_poll_get_info (context->display->renderer,
poll_fds, poll_fds,
n_poll_fds, n_poll_fds,
timeout); 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 static void
@ -581,9 +664,20 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
const CoglPollFD *poll_fds, const CoglPollFD *poll_fds,
int n_poll_fds) int n_poll_fds)
{ {
CoglDisplay *display = context->display;
CoglDisplayEGL *egl_display = display->winsys;
_cogl_xlib_renderer_poll_dispatch (context->display->renderer, _cogl_xlib_renderer_poll_dispatch (context->display->renderer,
poll_fds, poll_fds,
n_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 #ifdef EGL_KHR_image_pixmap
@ -726,6 +820,8 @@ _cogl_winsys_egl_xlib_get_vtable (void)
vtable.onscreen_set_visibility = vtable.onscreen_set_visibility =
_cogl_winsys_onscreen_set_visibility; _cogl_winsys_onscreen_set_visibility;
vtable.onscreen_set_resizable =
_cogl_winsys_onscreen_set_resizable;
vtable.onscreen_x11_get_window_xid = vtable.onscreen_x11_get_window_xid =
_cogl_winsys_onscreen_x11_get_window_xid; _cogl_winsys_onscreen_x11_get_window_xid;

View File

@ -80,6 +80,7 @@ typedef struct _CoglOnscreenGLX
GLXDrawable glxwin; GLXDrawable glxwin;
uint32_t last_swap_vsync_counter; uint32_t last_swap_vsync_counter;
CoglBool pending_swap_notify; CoglBool pending_swap_notify;
CoglBool pending_resize_notify;
} CoglOnscreenGLX; } CoglOnscreenGLX;
typedef struct _CoglTexturePixmapGLX typedef struct _CoglTexturePixmapGLX
@ -183,6 +184,32 @@ notify_swap_buffers (CoglContext *context, GLXDrawable drawable)
glx_onscreen->pending_swap_notify = TRUE; 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 static CoglFilterReturn
glx_event_filter_cb (XEvent *xevent, void *data) glx_event_filter_cb (XEvent *xevent, void *data)
{ {
@ -193,17 +220,10 @@ glx_event_filter_cb (XEvent *xevent, void *data)
if (xevent->type == ConfigureNotify) if (xevent->type == ConfigureNotify)
{ {
CoglOnscreen *onscreen = notify_resize (context,
find_onscreen_for_xid (context, xevent->xconfigure.window); xevent->xconfigure.window,
xevent->xconfigure.width,
if (onscreen) xevent->xconfigure.height);
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
_cogl_framebuffer_winsys_update_size (framebuffer,
xevent->xconfigure.width,
xevent->xconfigure.height);
}
/* we let ConfigureNotify pass through */ /* we let ConfigureNotify pass through */
return COGL_FILTER_CONTINUE; return COGL_FILTER_CONTINUE;
@ -1412,6 +1432,44 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin); XUnmapWindow (xlib_renderer->xdpy, xlib_onscreen->xwin);
} }
static void
_cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen,
CoglBool resizable)
{
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 (resizable)
{
/* 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... */ /* XXX: This is a particularly hacky _cogl_winsys interface... */
static XVisualInfo * static XVisualInfo *
_cogl_winsys_xlib_get_visual_info (void) _cogl_winsys_xlib_get_visual_info (void)
@ -2004,13 +2062,13 @@ _cogl_winsys_poll_get_info (CoglContext *context,
/* If we've already got a pending swap notify then we'll dispatch /* If we've already got a pending swap notify then we'll dispatch
immediately */ immediately */
if (glx_display->pending_swap_notify) if (glx_display->pending_swap_notify || glx_display->pending_resize_notify)
*timeout = 0; *timeout = 0;
} }
static void static void
flush_pending_swap_notify_cb (void *data, flush_pending_notifications_cb (void *data,
void *user_data) void *user_data)
{ {
CoglFramebuffer *framebuffer = data; CoglFramebuffer *framebuffer = data;
@ -2024,6 +2082,12 @@ flush_pending_swap_notify_cb (void *data,
_cogl_onscreen_notify_swap_buffers (onscreen); _cogl_onscreen_notify_swap_buffers (onscreen);
glx_onscreen->pending_swap_notify = FALSE; glx_onscreen->pending_swap_notify = FALSE;
} }
if (glx_onscreen->pending_resize_notify)
{
_cogl_onscreen_notify_resize (onscreen);
glx_onscreen->pending_resize_notify = FALSE;
}
} }
} }
@ -2039,12 +2103,13 @@ _cogl_winsys_poll_dispatch (CoglContext *context,
poll_fds, poll_fds,
n_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, g_list_foreach (context->framebuffers,
flush_pending_swap_notify_cb, flush_pending_notifications_cb,
NULL); NULL);
glx_display->pending_swap_notify = FALSE; glx_display->pending_swap_notify = FALSE;
glx_display->pending_resize_notify = FALSE;
} }
} }
@ -2073,6 +2138,8 @@ static CoglWinsysVtable _cogl_winsys_vtable =
.onscreen_x11_get_window_xid = .onscreen_x11_get_window_xid =
_cogl_winsys_onscreen_x11_get_window_xid, _cogl_winsys_onscreen_x11_get_window_xid,
.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility, .onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility,
.onscreen_set_resizable =
_cogl_winsys_onscreen_set_resizable,
.poll_get_info = _cogl_winsys_poll_get_info, .poll_get_info = _cogl_winsys_poll_get_info,
.poll_dispatch = _cogl_winsys_poll_dispatch, .poll_dispatch = _cogl_winsys_poll_dispatch,

View File

@ -120,6 +120,9 @@ typedef struct _CoglWinsysVtable
const int *rectangles, const int *rectangles,
int n_rectangles); int n_rectangles);
void
(*onscreen_set_resizable) (CoglOnscreen *onscreen, CoglBool resizable);
#ifdef COGL_HAS_EGL_SUPPORT #ifdef COGL_HAS_EGL_SUPPORT
EGLDisplay EGLDisplay
(*context_egl_get_egl_display) (CoglContext *context); (*context_egl_get_egl_display) (CoglContext *context);

View File

@ -46,8 +46,9 @@ typedef struct _CoglRendererSdl
typedef struct _CoglDisplaySdl typedef struct _CoglDisplaySdl
{ {
SDL_Surface *surface; SDL_Surface *surface;
CoglBool has_onscreen; CoglOnscreen *onscreen;
Uint32 video_mode_flags; Uint32 video_mode_flags;
CoglBool pending_resize_notify;
} CoglDisplaySdl; } CoglDisplaySdl;
static CoglFuncPtr static CoglFuncPtr
@ -200,6 +201,39 @@ error:
return FALSE; 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 static CoglBool
_cogl_winsys_context_init (CoglContext *context, GError **error) _cogl_winsys_context_init (CoglContext *context, GError **error)
{ {
@ -209,6 +243,10 @@ _cogl_winsys_context_init (CoglContext *context, GError **error)
g_error ("cogl_sdl_renderer_set_event_type() or cogl_sdl_context_new() " g_error ("cogl_sdl_renderer_set_event_type() or cogl_sdl_context_new() "
"must be called during initialization"); "must be called during initialization");
_cogl_renderer_add_native_filter (renderer,
(CoglNativeFilterFunc)sdl_event_filter_cb,
context);
return _cogl_context_update_features (context, error); return _cogl_context_update_features (context, error);
} }
@ -229,7 +267,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
CoglDisplay *display = context->display; CoglDisplay *display = context->display;
CoglDisplaySdl *sdl_display = display->winsys; CoglDisplaySdl *sdl_display = display->winsys;
sdl_display->has_onscreen = FALSE; sdl_display->onscreen = NULL;
} }
static CoglBool static CoglBool
@ -242,7 +280,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
CoglDisplaySdl *sdl_display = display->winsys; CoglDisplaySdl *sdl_display = display->winsys;
int width, height; int width, height;
if (sdl_display->has_onscreen) if (sdl_display->onscreen)
{ {
g_set_error (error, COGL_WINSYS_ERROR, g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_ONSCREEN, COGL_WINSYS_ERROR_CREATE_ONSCREEN,
@ -275,7 +313,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
sdl_display->surface->w, sdl_display->surface->w,
sdl_display->surface->h); sdl_display->surface->h);
sdl_display->has_onscreen = TRUE; sdl_display->onscreen = onscreen;
return TRUE; return TRUE;
} }
@ -299,6 +337,49 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
/* SDL doesn't appear to provide a way to set this */ /* SDL doesn't appear to provide a way to set this */
} }
static void
_cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen,
CoglBool resizable)
{
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 (resizable)
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 * const CoglWinsysVtable *
_cogl_winsys_sdl_get_vtable (void) _cogl_winsys_sdl_get_vtable (void)
{ {
@ -330,6 +411,9 @@ _cogl_winsys_sdl_get_vtable (void)
vtable.onscreen_update_swap_throttled = vtable.onscreen_update_swap_throttled =
_cogl_winsys_onscreen_update_swap_throttled; _cogl_winsys_onscreen_update_swap_throttled;
vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility;
vtable.onscreen_set_resizable = _cogl_winsys_onscreen_set_resizable;
vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE; vtable_inited = TRUE;
} }

View File

@ -59,6 +59,8 @@ main (int argc, char **argv)
cogl_onscreen_show (onscreen); cogl_onscreen_show (onscreen);
data.fb = COGL_FRAMEBUFFER (onscreen); data.fb = COGL_FRAMEBUFFER (onscreen);
cogl_onscreen_set_resizable (onscreen, TRUE);
data.triangle = cogl_primitive_new_p2c4 (data.ctx, data.triangle = cogl_primitive_new_p2c4 (data.ctx,
COGL_VERTICES_MODE_TRIANGLES, COGL_VERTICES_MODE_TRIANGLES,
3, triangle_vertices); 3, triangle_vertices);

View File

@ -31,6 +31,16 @@ update_cogl_x11_event_mask (CoglOnscreen *onscreen,
&attrs); &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 int
main (int argc, char **argv) main (int argc, char **argv)
{ {
@ -149,6 +159,9 @@ main (int argc, char **argv)
fb = COGL_FRAMEBUFFER (onscreen); fb = COGL_FRAMEBUFFER (onscreen);
cogl_onscreen_set_resizable (onscreen, TRUE);
cogl_onscreen_add_resize_handler (onscreen, resize_handler, onscreen);
triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES, triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES,
3, triangle_vertices); 3, triangle_vertices);
pipeline = cogl_pipeline_new (ctx); pipeline = cogl_pipeline_new (ctx);
@ -170,13 +183,18 @@ main (int argc, char **argv)
} }
cogl_xlib_renderer_handle_event (renderer, &event); 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); cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
g_poll ((GPollFD *) poll_fds, n_poll_fds, 0); g_poll ((GPollFD *) poll_fds, n_poll_fds, 0);
cogl_poll_dispatch (ctx, poll_fds, n_poll_fds); 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; return 0;