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;
Window dummy_xwin;
CoglBool pending_swap_notify;
CoglBool pending_resize_notify;
} CoglGLXDisplay;
#endif /* __COGL_DISPLAY_GLX_PRIVATE_H */

View File

@ -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 resizable;
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 */

View File

@ -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;
@ -346,6 +354,22 @@ _cogl_onscreen_notify_swap_buffers (CoglOnscreen *onscreen)
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
_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_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,
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:
* @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);
_cogl_renderer_handle_native_event (context->display->renderer, event);
if (winsys->poll_dispatch)
winsys->poll_dispatch (context, NULL, 0);
}

View File

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

View File

@ -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_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
_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_resizable =
_cogl_winsys_onscreen_set_resizable;
vtable.onscreen_x11_get_window_xid =
_cogl_winsys_onscreen_x11_get_window_xid;

View File

@ -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
@ -183,6 +184,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)
{
@ -193,17 +220,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;
@ -1412,6 +1432,44 @@ _cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
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... */
static XVisualInfo *
_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
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;
@ -2024,6 +2082,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;
}
}
}
@ -2039,12 +2103,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;
}
}
@ -2073,6 +2138,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_resizable =
_cogl_winsys_onscreen_set_resizable,
.poll_get_info = _cogl_winsys_poll_get_info,
.poll_dispatch = _cogl_winsys_poll_dispatch,

View File

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

View File

@ -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
@ -200,6 +201,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)
{
@ -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() "
"must be called during initialization");
_cogl_renderer_add_native_filter (renderer,
(CoglNativeFilterFunc)sdl_event_filter_cb,
context);
return _cogl_context_update_features (context, error);
}
@ -229,7 +267,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
@ -242,7 +280,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,
@ -275,7 +313,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;
}
@ -299,6 +337,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_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 *
_cogl_winsys_sdl_get_vtable (void)
{
@ -330,6 +411,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_resizable = _cogl_winsys_onscreen_set_resizable;
vtable.poll_dispatch = _cogl_winsys_poll_dispatch;
vtable_inited = TRUE;
}

View File

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

View File

@ -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_resizable (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;