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:
parent
72f992effe
commit
df51574116
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user