/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( WM_Unique, "WM/UniQuE", "UniQuE - Universal Quark Emitter" ); DFB_WINDOW_MANAGER( unique ); /**************************************************************************************************/ typedef struct { int magic; CoreWindowStack *stack; UniqueContext *context; GlobalReaction context_reaction; } StackData; typedef struct { int magic; UniqueContext *context; UniqueWindow *window; GlobalReaction window_reaction; } WindowData; /**************************************************************************************************/ static ReactionResult context_notify( WMData *data, const UniqueContextNotification *notification, void *ctx ) { StackData *stack_data = ctx; D_ASSERT( data != NULL ); D_ASSERT( notification != NULL ); D_ASSERT( notification->context != NULL ); D_MAGIC_ASSERT( stack_data, StackData ); D_ASSERT( notification->context == stack_data->context ); D_MAGIC_ASSERT( stack_data->context, UniqueContext ); D_ASSERT( ! D_FLAGS_IS_SET( notification->flags, ~UCNF_ALL ) ); D_DEBUG_AT( WM_Unique, "context_notify( wm_data %p, stack_data %p )\n", data, stack_data ); if (notification->flags & UCNF_DESTROYED) { D_DEBUG_AT( WM_Unique, " -> context destroyed.\n" ); if (notification->context == stack_data->context) stack_data->context = NULL; return RS_REMOVE; } return RS_OK; } static ReactionResult window_notify( WMData *data, const UniqueWindowNotification *notification, void *ctx ) { WindowData *window_data = ctx; D_ASSERT( data != NULL ); D_ASSERT( notification != NULL ); D_ASSERT( notification->window != NULL ); D_MAGIC_ASSERT( window_data, WindowData ); D_ASSERT( notification->window == window_data->window ); D_MAGIC_ASSERT( window_data->window, UniqueWindow ); D_ASSERT( ! D_FLAGS_IS_SET( notification->flags, ~UWNF_ALL ) ); D_DEBUG_AT( WM_Unique, "window_notify( wm_data %p, window_data %p )\n", data, window_data ); if (notification->flags & UWNF_DESTROYED) { D_DEBUG_AT( WM_Unique, " -> window destroyed.\n" ); window_data->window = NULL; return RS_REMOVE; } return RS_OK; } /**************************************************************************************************/ static void initialize_data( CoreDFB *core, WMData *data, WMShared *shared ) { D_ASSERT( data != NULL ); /* Initialize local data. */ data->core = core; data->world = dfb_core_world( core ); data->shared = shared; data->module_abi = UNIQUE_WM_ABI_VERSION; /* Set module callbacks. */ data->context_notify = context_notify; data->window_notify = window_notify; } /**************************************************************************************************/ static void wm_get_info( CoreWMInfo *info ) { info->version.major = 0; info->version.minor = 4; info->version.binary = UNIQUE_WM_ABI_VERSION; snprintf( info->name, DFB_CORE_WM_INFO_NAME_LENGTH, "UniQuE" ); snprintf( info->vendor, DFB_CORE_WM_INFO_VENDOR_LENGTH, "Denis Oliver Kropp" ); info->wm_data_size = sizeof(WMData); info->wm_shared_size = sizeof(WMShared); info->stack_data_size = sizeof(StackData); info->window_data_size = sizeof(WindowData); } static DFBResult wm_initialize( CoreDFB *core, void *wm_data, void *shared_data ) { WMData *data = wm_data; WMShared *shared = shared_data; D_DEBUG_AT( WM_Unique, "wm_initialize()\n" ); initialize_data( core, data, shared ); D_MAGIC_SET( shared, WMShared ); return unique_wm_module_init( core, data, shared, true ); } static DFBResult wm_join( CoreDFB *core, void *wm_data, void *shared_data ) { WMData *data = wm_data; WMShared *shared = shared_data; D_DEBUG_AT( WM_Unique, "wm_join()\n" ); initialize_data( core, data, shared ); return unique_wm_module_init( core, data, shared, false ); } static DFBResult wm_shutdown( bool emergency, void *wm_data, void *shared_data ) { WMShared *shared = shared_data; (void) shared; D_DEBUG_AT( WM_Unique, "wm_shutdown()\n" ); unique_wm_module_deinit( wm_data, shared_data, true, emergency ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult wm_leave( bool emergency, void *wm_data, void *shared_data ) { D_DEBUG_AT( WM_Unique, "wm_leave()\n" ); unique_wm_module_deinit( wm_data, shared_data, false, emergency ); return DFB_OK; } static DFBResult wm_suspend( void *wm_data, void *shared_data ) { D_DEBUG_AT( WM_Unique, "wm_suspend()\n" ); return DFB_OK; } static DFBResult wm_resume( void *wm_data, void *shared_data ) { D_DEBUG_AT( WM_Unique, "wm_resume()\n" ); return DFB_OK; } static DFBResult wm_post_init( void *wm_data, void *shared_data ) { D_DEBUG_AT( WM_Unique, "wm_post_init()\n" ); return DFB_OK; } /**************************************************************************************************/ static DFBResult wm_init_stack( CoreWindowStack *stack, void *wm_data, void *stack_data ) { DFBResult ret; StackData *data = stack_data; WMData *wmdata = wm_data; CoreLayerContext *context; CoreLayerRegion *region; D_ASSERT( stack != NULL ); D_ASSERT( stack->context != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); context = stack->context; D_ASSERT( context != NULL ); ret = dfb_layer_context_get_primary_region( context, true, ®ion ); if (ret) { D_DERROR( ret, "WM/UniQuE: Could not get the primary region!\n" ); return ret; } /* Create the unique context. */ ret = unique_context_create( wmdata->core, stack, region, context->layer_id, wmdata->shared, &data->context ); dfb_layer_region_unref( region ); if (ret) { D_DERROR( ret, "WM/UniQuE: Could not create the context!\n" ); return ret; } /* Attach the global context listener. */ ret = unique_context_attach_global( data->context, UNIQUE_WM_MODULE_CONTEXT_LISTENER, data, &data->context_reaction ); if (ret) { unique_context_unref( data->context ); D_DERROR( ret, "WM/UniQuE: Could not attach global context listener!\n" ); return ret; } /* Inherit all local references from the layer context. */ ret = unique_context_inherit( data->context, context ); unique_context_unref( data->context ); if (ret) { unique_context_detach_global( data->context, &data->context_reaction ); D_DERROR( ret, "WM/UniQuE: Could not inherit from layer context!\n" ); return ret; } data->stack = stack; D_MAGIC_SET( data, StackData ); return DFB_OK; } static DFBResult wm_close_stack( CoreWindowStack *stack, void *wm_data, void *stack_data ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_MAGIC_ASSERT( data, StackData ); D_ASSUME( data->context == NULL ); if (data->context) unique_context_detach_global( data->context, &data->context_reaction ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult wm_set_active( CoreWindowStack *stack, void *wm_data, void *stack_data, bool active ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_MAGIC_ASSERT( data, StackData ); D_DEBUG_AT( WM_Unique, "%s( stack %p, wm_data %p, stack_data %p, %sactive )\n", __FUNCTION__, stack, wm_data, stack_data, active ? "" : "in" ); if (!data->context) { D_ASSERT( !active ); return DFB_OK; } return unique_context_set_active( data->context, active ); } static DFBResult wm_resize_stack( CoreWindowStack *stack, void *wm_data, void *stack_data, int width, int height ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; return unique_context_resize( data->context, width, height ); } static DFBResult wm_process_input( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBInputEvent *event ) { StackData *data = stack_data; (void) data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( event != NULL ); D_MAGIC_ASSERT( data, StackData ); return DFB_OK; } static DFBResult wm_flush_keys( CoreWindowStack *stack, void *wm_data, void *stack_data ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; return unique_context_flush_keys( data->context ); } static DFBResult wm_window_at( CoreWindowStack *stack, void *wm_data, void *stack_data, int x, int y, CoreWindow **ret_window ) { DFBResult ret; UniqueWindow *window; StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( ret_window != NULL ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; ret = unique_context_window_at( data->context, x, y, &window ); if (ret) return ret; D_MAGIC_ASSERT( window, UniqueWindow ); *ret_window = window->window; return DFB_OK; } static DFBResult wm_window_lookup( CoreWindowStack *stack, void *wm_data, void *stack_data, DFBWindowID window_id, CoreWindow **ret_window ) { DFBResult ret; UniqueWindow *window; StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( ret_window != NULL ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; ret = unique_context_lookup_window( data->context, window_id, &window ); if (ret) return ret; D_MAGIC_ASSERT( window, UniqueWindow ); *ret_window = window->window; return DFB_OK; } static DFBResult wm_enum_windows( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWMWindowCallback callback, void *callback_ctx ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( callback != NULL ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; return unique_context_enum_windows( data->context, callback, callback_ctx ); } /**************************************************************************************************/ static DFBResult wm_get_insets( CoreWindowStack *stack, CoreWindow *window, DFBInsets *insets ) { if( insets ) { insets->l=0; insets->t=0; insets->r=0; insets->b=0; } return DFB_OK; } static DFBResult wm_preconfigure_window( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ) { return DFB_OK; } static DFBResult wm_set_window_property( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void *value, void **ret_old_value ) { D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( window != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( key != NULL ); fusion_object_set_property((FusionObject*)window, key,value,ret_old_value); return DFB_OK; } static DFBResult wm_get_window_property( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **ret_value ) { D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( window != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( key != NULL ); D_ASSERT( ret_value != NULL ); *ret_value=fusion_object_get_property((FusionObject*)window,key); return DFB_OK; } static DFBResult wm_remove_window_property( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **ret_value ) { D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( window != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( key != NULL ); fusion_object_remove_property((FusionObject*)window,key,ret_value); return DFB_OK; } static DFBResult wm_add_window( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ) { DFBResult ret; StackData *sdata = stack_data; WindowData *data = window_data; WMData *wmdata = wm_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( window != NULL ); D_ASSERT( window_data != NULL ); D_MAGIC_ASSERT( sdata, StackData ); D_MAGIC_ASSERT( sdata->context, UniqueContext ); data->context = sdata->context; /* Create the unique window. */ ret = unique_window_create( wmdata->core, window, data->context, window->caps, &window->config, &data->window ); if (ret) { D_DERROR( ret, "WM/UniQuE: Could not create window!\n" ); return ret; } /* Attach the global window listener. */ ret = unique_window_attach_global( data->window, UNIQUE_WM_MODULE_WINDOW_LISTENER, data, &data->window_reaction ); if (ret) { unique_window_unref( data->window ); D_DERROR( ret, "WM/UniQuE: Could not attach global window listener!\n" ); return ret; } /* Inherit all local references from the layer window. */ ret = unique_window_inherit( data->window, window ); unique_window_unref( data->window ); if (ret) { unique_window_detach_global( data->window, &data->window_reaction ); D_DERROR( ret, "WM/UniQuE: Could not inherit from core window!\n" ); return ret; } unique_window_get_config( data->window, &window->config ); D_MAGIC_SET( data, WindowData ); return DFB_OK; } static DFBResult wm_remove_window( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ) { WindowData *data = window_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_ASSERT( window != NULL ); D_ASSERT( window_data != NULL ); D_MAGIC_ASSERT( data, WindowData ); // D_ASSUME( data->window == NULL ); if (data->window) unique_window_detach_global( data->window, &data->window_reaction ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult wm_set_window_config( CoreWindow *window, void *wm_data, void *window_data, const CoreWindowConfig *config, CoreWindowConfigFlags flags ) { DFBResult ret; WindowData *data = window_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( config != NULL ); D_MAGIC_ASSERT( data, WindowData ); if (!data->window) return DFB_DESTROYED; ret = unique_window_set_config( data->window, config, flags ); unique_window_get_config( data->window, &window->config ); return ret; } static DFBResult wm_restack_window( CoreWindow *window, void *wm_data, void *window_data, CoreWindow *relative, void *relative_data, int relation ) { WindowData *data = window_data; WindowData *rel_data = relative_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); D_MAGIC_ASSERT( data, WindowData ); D_ASSERT( relative == NULL || relative_data != NULL ); D_ASSERT( relative == NULL || relative == window || relation != 0); if (!data->window) return DFB_DESTROYED; return unique_window_restack( data->window, rel_data ? rel_data->window : NULL, relation ); } static DFBResult wm_grab( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ) { WindowData *data = window_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( grab != NULL ); D_MAGIC_ASSERT( data, WindowData ); if (!data->window) return DFB_DESTROYED; return unique_window_grab( data->window, grab ); } static DFBResult wm_ungrab( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ) { WindowData *data = window_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); D_ASSERT( grab != NULL ); D_MAGIC_ASSERT( data, WindowData ); if (!data->window) return DFB_DESTROYED; return unique_window_ungrab( data->window, grab ); } static DFBResult wm_request_focus( CoreWindow *window, void *wm_data, void *window_data ) { WindowData *data = window_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); D_MAGIC_ASSERT( data, WindowData ); if (!data->window) return DFB_DESTROYED; return unique_window_request_focus( data->window ); } /**************************************************************************************************/ static DFBResult wm_update_stack( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { StackData *data = stack_data; D_ASSERT( stack != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); DFB_REGION_ASSERT( region ); D_MAGIC_ASSERT( data, StackData ); if (!data->context) return DFB_DESTROYED; return unique_context_update( data->context, region, 1, flags ); } static DFBResult wm_update_window( CoreWindow *window, void *wm_data, void *window_data, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { WindowData *data = window_data; D_ASSERT( window != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( window_data != NULL ); DFB_REGION_ASSERT_IF( region ); D_MAGIC_ASSERT( data, WindowData ); if (!data->window) return DFB_DESTROYED; return unique_window_update( data->window, region, flags ); } /**************************************************************************************************/ /* HACK: implementation dumped in here for now, will move into context */ static DFBResult wm_update_cursor( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreCursorUpdateFlags flags ) { DFBResult ret; DFBRegion old_region; WMData *wmdata = wm_data; StackData *data = stack_data; bool restored = false; CoreLayer *layer; CoreLayerRegion *region; CardState *state; CoreSurface *surface; UniqueContext *context; D_ASSERT( stack != NULL ); D_ASSERT( stack->context != NULL ); D_ASSERT( wm_data != NULL ); D_ASSERT( stack_data != NULL ); D_MAGIC_ASSERT( data, StackData ); context = data->context; D_MAGIC_ASSERT( context, UniqueContext ); /* Optimize case of invisible cursor moving. */ if (!(flags & ~(CCUF_POSITION | CCUF_SHAPE)) && (!stack->cursor.opacity || !stack->cursor.enabled)) { context->cursor_bs_valid = false; return DFB_OK; } layer = dfb_layer_at( context->layer_id ); state = &layer->state; region = context->region; surface = context->surface; D_ASSERT( region != NULL ); D_ASSERT( surface != NULL ); if (flags & CCUF_ENABLE) { CoreSurface *cursor_bs; DFBSurfaceCapabilities caps = DSCAPS_NONE; dfb_surface_caps_apply_policy( stack->cursor.policy, &caps ); D_ASSERT( context->cursor_bs == NULL ); /* Create the cursor backing store surface. */ ret = dfb_surface_create_simple( wmdata->core, stack->cursor.size.w, stack->cursor.size.h, region->config.format, caps, CSTF_SHARED | CSTF_CURSOR, 0, /* FIXME: no shared cursor objects, no cursor id */ NULL, &cursor_bs ); if (ret) { D_ERROR( "WM/Default: Failed creating backing store for cursor!\n" ); return ret; } ret = dfb_surface_globalize( cursor_bs ); D_ASSERT( ret == DFB_OK ); /* Ensure valid back buffer for now. * FIXME: Keep a flag to know when back/front have been swapped and need a sync. */ switch (region->config.buffermode) { case DLBM_BACKVIDEO: case DLBM_TRIPLE: dfb_gfx_copy( surface, surface, NULL ); break; default: break; } context->cursor_bs = cursor_bs; } else { D_ASSERT( context->cursor_bs != NULL ); /* restore region under cursor */ if (context->cursor_drawn) { DFBRectangle rect = { 0, 0, context->cursor_region.x2 - context->cursor_region.x1 + 1, context->cursor_region.y2 - context->cursor_region.y1 + 1 }; D_ASSERT( stack->cursor.opacity || (flags & CCUF_OPACITY) ); D_ASSERT( context->cursor_bs_valid ); dfb_gfx_copy_to( context->cursor_bs, surface, &rect, context->cursor_region.x1, context->cursor_region.y1, false ); context->cursor_drawn = false; old_region = context->cursor_region; restored = true; } if (flags & CCUF_SIZE) { ret = dfb_surface_reformat( context->cursor_bs, stack->cursor.size.w, stack->cursor.size.h, context->cursor_bs->config.format ); if (ret) { D_ERROR( "WM/Default: Failed resizing backing store for cursor!\n" ); return ret; } } } if (flags & (CCUF_ENABLE | CCUF_POSITION | CCUF_SIZE | CCUF_OPACITY)) { context->cursor_bs_valid = false; context->cursor_region.x1 = stack->cursor.x - stack->cursor.hot.x; context->cursor_region.y1 = stack->cursor.y - stack->cursor.hot.y; context->cursor_region.x2 = context->cursor_region.x1 + stack->cursor.size.w - 1; context->cursor_region.y2 = context->cursor_region.y1 + stack->cursor.size.h - 1; if (!dfb_region_intersect( &context->cursor_region, 0, 0, stack->width - 1, stack->height - 1 )) { D_BUG( "invalid cursor region" ); return DFB_BUG; } } D_ASSERT( context->cursor_bs != NULL ); if (flags & CCUF_DISABLE) { dfb_surface_unlink( &context->cursor_bs ); } else if (stack->cursor.opacity) { /* backup region under cursor */ if (!context->cursor_bs_valid) { DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &context->cursor_region ); D_ASSERT( !context->cursor_drawn ); /* FIXME: this requires using blitted flipping all the time, but fixing it seems impossible, for now DSFLIP_BLIT is forced in repaint_stack() when the cursor is enabled. */ dfb_gfx_copy_to( surface, context->cursor_bs, &rect, 0, 0, true ); context->cursor_bs_valid = true; } /* Set destination. */ state->destination = surface; state->modified |= SMF_DESTINATION; /* Set clipping region. */ dfb_state_set_clip( state, &context->cursor_region ); /* draw cursor */ unique_draw_cursor( stack, context, state, &context->cursor_region ); /* Reset destination. */ state->destination = NULL; state->modified |= SMF_DESTINATION; context->cursor_drawn = true; if (restored) { if (dfb_region_region_intersects( &old_region, &context->cursor_region )) dfb_region_region_union( &old_region, &context->cursor_region ); else dfb_layer_region_flip_update( region, &context->cursor_region, DSFLIP_BLIT ); dfb_layer_region_flip_update( region, &old_region, DSFLIP_BLIT ); } else dfb_layer_region_flip_update( region, &context->cursor_region, DSFLIP_BLIT ); } else if (restored) dfb_layer_region_flip_update( region, &old_region, DSFLIP_BLIT ); return DFB_OK; }