/* (c) Copyright 2006-2007 directfb.org All rights reserved. Written by Denis Oliver Kropp . 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. */ //#define DIRECT_ENABLE_DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sawman_config.h" #include "sawman_draw.h" #include "isawman.h" #ifndef DIRECTFB_PURE_VOODOO D_DEBUG_DOMAIN( SaWMan_Auto, "SaWMan/Auto", "SaWMan auto configuration" ); D_DEBUG_DOMAIN( SaWMan_Update, "SaWMan/Update", "SaWMan window manager updates" ); D_DEBUG_DOMAIN( SaWMan_Geometry, "SaWMan/Geometry", "SaWMan window manager geometry" ); D_DEBUG_DOMAIN( SaWMan_Stacking, "SaWMan/Stacking", "SaWMan window manager stacking" ); D_DEBUG_DOMAIN( SaWMan_FlipOnce, "SaWMan/FlipOnce", "SaWMan window manager flip once" ); D_DEBUG_DOMAIN( SaWMan_Cursor, "SaWMan/Cursor", "SaWMan window manager cursor" ); D_DEBUG_DOMAIN( SaWMan_Focus, "SaWMan/Focus", "SaWMan window manager focus" ); /* FIXME: avoid globals */ static SaWMan *m_sawman; static SaWManProcess *m_process; static FusionWorld *m_world; /**********************************************************************************************************************/ static void wind_of_change ( SaWMan *sawman, SaWManTier *tier, DFBRegion *update, DFBSurfaceFlipFlags flags, int current, int changed ); static void wind_of_showing( SaWMan *sawman, SaWManTier *tier, DFBRegion *update, int current, int changed, bool *ret_showing ); #endif // !DIRECTFB_PURE_VOODOO /**********************************************************************************************************************/ static DFBResult CreateRemote( const char *host, int session, ISaWMan **ret_sawman ); /**********************************************************************************************************************/ DirectResult SaWManInit( int *argc, char ***argv ) { #ifndef DIRECTFB_PURE_VOODOO return sawman_config_init( argc, argv ); #else return DR_OK; #endif } DirectResult SaWManCreate( ISaWMan **ret_sawman ) { #ifndef DIRECTFB_PURE_VOODOO DirectResult ret; ISaWMan *sawman; #endif if (!ret_sawman) return DFB_INVARG; direct_initialize(); #ifndef DIRECTFB_PURE_VOODOO if (dfb_config->remote.host) return CreateRemote( dfb_config->remote.host, dfb_config->remote.session, ret_sawman ); CoreDFB *core; dfb_core_create( &core ); if (!m_sawman) { D_ERROR( "SaWManCreate: No running SaWMan detected! Did you use the 'wm=sawman' option?\n" ); return DFB_NOIMPL; } D_MAGIC_ASSERT( m_sawman, SaWMan ); D_MAGIC_ASSERT( m_process, SaWManProcess ); DIRECT_ALLOCATE_INTERFACE( sawman, ISaWMan ); ret = ISaWMan_Construct( sawman, m_sawman, m_process ); if (ret) return ret; *ret_sawman = sawman; return DFB_OK; #else return CreateRemote( dfb_config->remote.host ?: "", dfb_config->remote.session, ret_sawman ); #endif } /**********************************************************************************************************************/ static DFBResult CreateRemote( const char *host, int session, ISaWMan **ret_sawman ) { DFBResult ret; DirectInterfaceFuncs *funcs; void *interface; D_ASSERT( host != NULL ); D_ASSERT( ret_sawman != NULL ); ret = DirectGetInterface( &funcs, "ISaWMan", "Requestor", NULL, NULL ); if (ret) return ret; ret = funcs->Allocate( &interface ); if (ret) return ret; ret = funcs->Construct( interface, host, session ); if (ret) return ret; *ret_sawman = interface; return DFB_OK; } /**********************************************************************************************************************/ #ifndef DIRECTFB_PURE_VOODOO static DirectResult register_process( SaWMan *sawman, SaWManProcessFlags flags, FusionWorld *world ) { DirectResult ret; SaWManProcess *process; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); /* Allocate process data. */ process = SHCALLOC( sawman->shmpool, 1, sizeof(SaWManProcess) ); if (!process) return D_OOSHM(); /* Initialize process data. */ process->pid = getpid(); process->fusion_id = fusion_id( world ); process->flags = flags; /* Initialize reference counter. */ ret = fusion_ref_init( &process->ref, "SaWMan Process", world ); if (ret) { D_DERROR( ret, "SaWMan/Register: fusion_ref_init() failed!\n" ); goto error_ref; } /* Add a local reference. */ ret = fusion_ref_up( &process->ref, false ); if (ret) { D_DERROR( ret, "SaWMan/Register: fusion_ref_up() failed!\n" ); goto error; } /* Set the process watcher on this. */ ret = fusion_ref_watch( &process->ref, &sawman->process_watch, process->pid ); if (ret) { D_DERROR( ret, "SaWMan/Register: fusion_ref_watch() failed!\n" ); goto error; } D_MAGIC_SET( process, SaWManProcess ); /* Add process to list. */ direct_list_append( &sawman->processes, &process->link ); /* Call application manager executable. */ sawman_call( sawman, SWMCID_PROCESS_ADDED, process ); /* Set global singleton. */ m_process = process; return DFB_OK; error: fusion_ref_destroy( &process->ref ); error_ref: SHFREE( sawman->shmpool, process ); return ret; } static DirectResult unregister_process( SaWMan *sawman, SaWManProcess *process ) { D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( process, SaWManProcess ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); /* Destroy reference counter. */ fusion_ref_destroy( &process->ref ); /* Remove process from list. */ direct_list_remove( &sawman->processes, &process->link ); /* Unregister manager process? */ if (process->flags & SWMPF_MANAGER) { D_ASSERT( sawman->manager.present ); /* Destroy manager call, unless it was another process. */ if (m_process == process) fusion_call_destroy( &sawman->manager.call ); else sawman->manager.call.handler = NULL; /* FIXME: avoid failing assertion in fusion_call_init() */ /* Ready for new manager. */ sawman->manager.present = false; } else { /* Call application manager executable. */ sawman_call( sawman, SWMCID_PROCESS_REMOVED, process ); } D_MAGIC_CLEAR( process ); /* Deallocate process data. */ SHFREE( sawman->shmpool, process ); return DFB_OK; } /**********************************************************************************************************************/ static FusionCallHandlerResult process_watcher( int caller, int call_arg, void *call_ptr, void *ctx, unsigned int serial, int *ret_val ) { DFBResult ret; SaWMan *sawman = ctx; SaWManProcess *process; D_MAGIC_ASSERT( sawman, SaWMan ); /* Lookup process by pid. */ direct_list_foreach (process, sawman->processes) { D_MAGIC_ASSERT( process, SaWManProcess ); if (process->pid == call_arg) break; } if (!process) { D_BUG( "process with pid %d not found", call_arg ); *ret_val = DFB_BUG; return FCHR_RETURN; } D_INFO( "SaWMan/Watcher: Process %d [%lu] has exited%s\n", process->pid, process->fusion_id, (process->flags & SWMPF_EXITING) ? "." : " ABNORMALLY!" ); ret = sawman_lock( sawman ); if (ret) D_DERROR( ret, "SaWMan/%s(): sawman_lock() failed!\n", __FUNCTION__ ); else { unregister_process( sawman, process ); sawman_unlock( sawman ); } return FCHR_RETURN; } static FusionCallHandlerResult manager_call_handler( int caller, int call_arg, void *call_ptr, void *ctx, unsigned int serial, int *ret_val ) { DirectResult ret; SaWMan *sawman = ctx; SaWManCallID call = call_arg; D_MAGIC_ASSERT( sawman, SaWMan ); /* Last mile of dispatch. */ switch (call) { case SWMCID_START: if (sawman->manager.callbacks.Start) { pid_t pid; ret = sawman->manager.callbacks.Start( sawman->manager.context, call_ptr, &pid ); if (ret) *ret_val = ret; else *ret_val = -pid; } break; case SWMCID_STOP: if (sawman->manager.callbacks.Stop) *ret_val = sawman->manager.callbacks.Stop( sawman->manager.context, (long) call_ptr, caller ); break; case SWMCID_PROCESS_ADDED: if (sawman->manager.callbacks.ProcessAdded) *ret_val = sawman->manager.callbacks.ProcessAdded( sawman->manager.context, call_ptr ); break; case SWMCID_PROCESS_REMOVED: if (sawman->manager.callbacks.ProcessRemoved) *ret_val = sawman->manager.callbacks.ProcessRemoved( sawman->manager.context, call_ptr ); break; case SWMCID_INPUT_FILTER: if (sawman->manager.callbacks.InputFilter) *ret_val = sawman->manager.callbacks.InputFilter( sawman->manager.context, call_ptr ); break; case SWMCID_WINDOW_PRECONFIG: if (sawman->manager.callbacks.WindowPreConfig) *ret_val = sawman->manager.callbacks.WindowPreConfig( sawman->manager.context, call_ptr ); break; case SWMCID_WINDOW_ADDED: if (sawman->manager.callbacks.WindowAdded) *ret_val = sawman->manager.callbacks.WindowAdded( sawman->manager.context, call_ptr ); break; case SWMCID_WINDOW_REMOVED: if (sawman->manager.callbacks.WindowRemoved) *ret_val = sawman->manager.callbacks.WindowRemoved( sawman->manager.context, call_ptr ); break; case SWMCID_WINDOW_RECONFIG: if (sawman->manager.callbacks.WindowReconfig) *ret_val = sawman->manager.callbacks.WindowReconfig( sawman->manager.context, call_ptr ); break; case SWMCID_WINDOW_RESTACK: if (sawman->manager.callbacks.WindowRestack) *ret_val = sawman->manager.callbacks.WindowRestack( sawman->manager.context, sawman->callback.handle, sawman->callback.relative, (SaWManWindowRelation)call_ptr ); break; case SWMCID_STACK_RESIZED: if (sawman->manager.callbacks.StackResized) *ret_val = sawman->manager.callbacks.StackResized( sawman->manager.context, call_ptr ); break; case SWMCID_SWITCH_FOCUS: if (sawman->manager.callbacks.SwitchFocus) *ret_val = sawman->manager.callbacks.SwitchFocus( sawman->manager.context, (SaWManWindowHandle)call_ptr ); break; case SWMCID_LAYER_RECONFIG: if (sawman->manager.callbacks.LayerReconfig) *ret_val = sawman->manager.callbacks.LayerReconfig( sawman->manager.context, call_ptr ); break; default: *ret_val = DFB_NOIMPL; } return FCHR_RETURN; } /**********************************************************************************************************************/ /**********************************************************************************************************************/ static DFBResult init_hw_cursor( SaWMan *sawman ) { DFBResult ret; sawman->cursor.layer = dfb_layer_at( sawman_config->cursor.layer_id ); D_ASSERT( sawman->cursor.layer != NULL ); ret = dfb_layer_create_context( sawman->cursor.layer, &sawman->cursor.context ); if (ret) { D_DERROR( ret, "SaWMan/Cursor: Could not create context at layer (id %u)!\n", sawman_config->cursor.layer_id ); return ret; } ret = dfb_layer_region_create( sawman->cursor.context, &sawman->cursor.region ); if (ret) { D_DERROR( ret, "SaWMan/Cursor: Could not create region at layer (id %u)!\n", sawman_config->cursor.layer_id ); dfb_layer_context_unref( sawman->cursor.context ); return ret; } dfb_layer_activate_context( sawman->cursor.layer, sawman->cursor.context ); return DFB_OK; } /**********************************************************************************************************************/ static DirectResult add_tier( SaWMan *sawman, FusionWorld *world, DFBDisplayLayerID layer_id, SaWManStackingClasses classes ) { SaWManTier *tier; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( layer_id >= 0 ); D_ASSERT( layer_id < MAX_LAYERS ); D_ASSERT( (classes & 7) != 0 ); D_ASSERT( (classes & ~7) == 0 ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); direct_list_foreach (tier, sawman->tiers) { D_MAGIC_ASSERT( tier, SaWManTier ); if (tier->classes & classes) { D_ERROR( "SaWMan/Tiers: Cannot add tier for layer %d's classes 0x%x which collides with " "layer %d's classes 0x%x!\n", layer_id, classes, tier->layer_id, tier->classes ); return DFB_BUSY; } if (tier->layer_id == layer_id) { D_ERROR( "SaWMan/Tiers: Cannot add tier with layer %d which is already added!\n", layer_id ); return DFB_BUSY; } } tier = SHCALLOC( sawman->shmpool, 1, sizeof(SaWManTier) ); if (!tier) return D_OOSHM(); tier->layer_id = layer_id; tier->classes = classes; tier->reactor = fusion_reactor_new( 0, "SaWMan Tier", world ); dfb_updates_init( &tier->updates, tier->update_regions, SAWMAN_MAX_UPDATE_REGIONS ); D_MAGIC_SET( tier, SaWManTier ); direct_list_append( &sawman->tiers, &tier->link ); return DFB_OK; } /**********************************************************************************************************************/ DirectResult sawman_initialize( SaWMan *sawman, FusionWorld *world, SaWManProcess **ret_process ) { int i; DirectResult ret; GraphicsDeviceInfo info; D_ASSERT( sawman != NULL ); D_ASSERT( world != NULL ); D_ASSERT( m_sawman == NULL ); /* Initialize process watcher call. */ ret = fusion_call_init( &sawman->process_watch, process_watcher, sawman, world ); if (ret) return ret; /* Create shared memory pool. */ ret = fusion_shm_pool_create( world, "SaWMan Pool", 0x100000, fusion_config->debugshm, &sawman->shmpool ); if (ret) goto error; /* Initialize lock. */ fusion_skirmish_init( &sawman->lock, "SaWMan", world ); /* Initialize window layout vector. */ fusion_vector_init( &sawman->layout, 8, sawman->shmpool ); /* Default to HW Scaling if supported. */ if (dfb_gfxcard_get_device_info( &info ), info.caps.accel & DFXL_STRETCHBLIT) sawman->scaling_mode = SWMSM_STANDARD; /* Initialize grabbed keys. */ for (i=0; ikeys[i].code = -1; D_MAGIC_SET( sawman, SaWMan ); sawman_lock( sawman ); sawman->resolution = sawman_config->resolution; /* Initialize tiers. */ for (i=0; ilayers); i++) { if (!dfb_config->layers[i].stacking) continue; ret = add_tier( sawman, world, i, dfb_config->layers[i].stacking ); if (ret) { sawman_unlock( sawman ); D_MAGIC_CLEAR( sawman ); goto error; } } /* Set global singleton. */ m_sawman = sawman; m_world = world; /* Register ourself as a new process. */ ret = register_process( sawman, SWMPF_MASTER, world ); if (ret) { sawman_unlock( sawman ); D_MAGIC_CLEAR( sawman ); goto error; } sawman_unlock( sawman ); if (ret_process) *ret_process = m_process; return DFB_OK; error: if (sawman->tiers) { SaWManTier *tier; DirectLink *next; direct_list_foreach_safe (tier, next, sawman->tiers) { D_MAGIC_CLEAR( tier ); SHFREE( sawman->shmpool, tier ); } } fusion_call_destroy( &sawman->process_watch ); m_sawman = NULL; m_world = NULL; m_process = NULL; return ret; } DirectResult sawman_post_init( SaWMan *sawman, FusionWorld *world ) { DFBResult ret; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( world != NULL ); D_ASSERT( m_sawman == sawman ); D_ASSERT( m_world == world ); D_MAGIC_ASSERT( m_process, SaWManProcess ); sawman_lock( sawman ); /* Initialize HW Cursor? */ if (sawman_config->cursor.hw) { ret = init_hw_cursor( sawman ); if (ret) { sawman_unlock( sawman ); return ret; } } sawman_unlock( sawman ); return DFB_OK; } DirectResult sawman_join( SaWMan *sawman, FusionWorld *world, SaWManProcess **ret_process ) { DirectResult ret; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( world != NULL ); D_ASSERT( m_sawman == NULL ); /* Set global singleton. */ m_sawman = sawman; m_world = world; /* Lock SaWMan. */ ret = sawman_lock( sawman ); if (ret) goto error; /* Register ourself as a new process. */ ret = register_process( sawman, SWMPF_NONE, world ); /* Unlock SaWMan. */ sawman_unlock( sawman ); if (ret) goto error; if (ret_process) *ret_process = m_process; return DFB_OK; error: m_sawman = NULL; m_world = NULL; m_process = NULL; return ret; } DirectResult sawman_shutdown( SaWMan *sawman, FusionWorld *world ) { DirectResult ret; DirectLink *next; SaWManProcess *process; SaWManWindow *sawwin; SaWManGrabbedKey *key; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( world != NULL ); D_ASSERT( m_sawman == sawman ); D_ASSERT( m_world == world ); D_ASSERT( sawman->processes != NULL ); D_ASSERT( sawman->processes->next == NULL ); process = (SaWManProcess*) sawman->processes; D_ASSERT( process == m_process ); D_ASSERT( process->fusion_id == fusion_id( world ) ); /* Lock SaWMan. */ ret = sawman_lock( sawman ); if (ret) return ret; /* Shutdown our own process. */ unregister_process( sawman, process ); /* Clear global singleton. */ m_process = NULL; /* Destroy process watcher call. */ fusion_call_destroy( &sawman->process_watch ); D_ASSERT( sawman->processes == NULL ); D_ASSERT( !sawman->manager.present ); D_ASSUME( sawman->windows == NULL ); direct_list_foreach (sawwin, sawman->windows) { D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->window != NULL ); D_WARN( "window %d,%d-%dx%d still there", DFB_RECTANGLE_VALS( &sawwin->bounds ) ); sawwin->window->stack = NULL; } /* FIXME */ D_ASSUME( !sawman->windows ); D_ASSUME( !sawman->layout.count ); /* Destroy window layout vector. */ fusion_vector_destroy( &sawman->layout ); /* Destroy lock. */ fusion_skirmish_destroy( &sawman->lock ); /* Free grabbed keys. */ direct_list_foreach_safe (key, next, sawman->grabbed_keys) { SHFREE( key->owner->shmpool, key ); } D_MAGIC_CLEAR( sawman ); /* Destroy shared memory pool. */ fusion_shm_pool_destroy( world, sawman->shmpool ); /* Clear global singleton. */ m_sawman = NULL; m_world = NULL; return DFB_OK; } DirectResult sawman_leave( SaWMan *sawman, FusionWorld *world ) { D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( world != NULL ); D_ASSERT( m_sawman == sawman ); D_ASSERT( m_world == world ); D_MAGIC_ASSERT( m_process, SaWManProcess ); /* Set 'cleanly exiting' flag. */ m_process->flags |= SWMPF_EXITING; /* Clear global singletons. */ m_sawman = NULL; m_world = NULL; m_process = NULL; return DFB_OK; } /**********************************************************************************************************************/ DirectResult sawman_call( SaWMan *sawman, SaWManCallID call, void *ptr ) { int ret = DFB_FUSION; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); D_ASSERT( m_sawman == sawman ); /* Check for presence of manager. */ if (!sawman->manager.present) return DFB_NOIMPL; /* Avoid useless context switches etc. */ switch (call) { case SWMCID_START: if (!sawman->manager.callbacks.Start) return DFB_NOIMPL; break; case SWMCID_STOP: if (!sawman->manager.callbacks.Stop) return DFB_NOIMPL; break; case SWMCID_PROCESS_ADDED: if (!sawman->manager.callbacks.ProcessAdded) return DFB_NOIMPL; break; case SWMCID_PROCESS_REMOVED: if (!sawman->manager.callbacks.ProcessRemoved) return DFB_NOIMPL; break; case SWMCID_INPUT_FILTER: if (!sawman->manager.callbacks.InputFilter) return DFB_NOIMPL; break; case SWMCID_WINDOW_PRECONFIG: if (!sawman->manager.callbacks.WindowPreConfig) return DFB_NOIMPL; break; case SWMCID_WINDOW_ADDED: if (!sawman->manager.callbacks.WindowAdded) return DFB_NOIMPL; break; case SWMCID_WINDOW_REMOVED: if (!sawman->manager.callbacks.WindowRemoved) return DFB_NOIMPL; break; case SWMCID_WINDOW_RECONFIG: if (!sawman->manager.callbacks.WindowReconfig) return DFB_NOIMPL; break; case SWMCID_WINDOW_RESTACK: if (!sawman->manager.callbacks.WindowRestack) return DFB_NOIMPL; break; case SWMCID_STACK_RESIZED: if (!sawman->manager.callbacks.StackResized) return DFB_NOIMPL; break; case SWMCID_SWITCH_FOCUS: if (!sawman->manager.callbacks.SwitchFocus) return DFB_NOIMPL; break; case SWMCID_LAYER_RECONFIG: if (!sawman->manager.callbacks.LayerReconfig) return DFB_NOIMPL; break; } /* Execute the call in the manager executable. */ if (fusion_call_execute( &sawman->manager.call, FCEF_NONE, call, ptr, &ret )) return DFB_NOIMPL; return ret; } /**********************************************************************************************************************/ DirectResult sawman_register( SaWMan *sawman, const SaWManCallbacks *callbacks, void *context ) { DirectResult ret; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( callbacks != NULL ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); D_ASSERT( m_sawman == sawman ); D_ASSERT( m_world != NULL ); D_MAGIC_ASSERT( m_process, SaWManProcess ); /* Check if another manager already exists. */ if (sawman->manager.present) return DFB_BUSY; /* Initialize the call to the manager executable (ourself). */ ret = fusion_call_init( &sawman->manager.call, manager_call_handler, sawman, m_world ); if (ret) return ret; /* Initialize manager data. */ sawman->manager.callbacks = *callbacks; sawman->manager.context = context; /* Set manager flag for our process. */ m_process->flags |= SWMPF_MANAGER; /* Activate it at last. */ sawman->manager.present = true; return DFB_OK; } DirectResult sawman_switch_focus( SaWMan *sawman, SaWManWindow *to ) { DirectResult ret; DFBWindowEvent evt; SaWManWindow *from; D_DEBUG_AT( SaWMan_Focus, "%s( %p, to %p )\n", __FUNCTION__, sawman, to ); D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT_IF( to, SaWManWindow ); from = sawman->focused_window; D_MAGIC_ASSERT_IF( from, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); if (from == to) return DFB_OK; // PR brg36mgr#118432: [550r1ext][Unknown]Directfb changing focuswindow spontaneously. // if (to && to->caps & DWCAPS_NOFOCUS) if (to && to->window->caps & DWCAPS_NOFOCUS) { D_DEBUG_AT( SaWMan_Focus, " -> DWCAPS_NOFOCUS, discarding focus switch!\n" ); return DFB_OK; // PR brg36mgr#118432: [550r1ext][Unknown]Directfb changing focuswindow spontaneously. } if (to) { switch (ret = sawman_call( sawman, SWMCID_SWITCH_FOCUS, to )) { case DFB_OK: case DFB_NOIMPL: break; default: D_DEBUG_AT( SaWMan_Focus, " -> application manager returned '%s'\n", DirectFBErrorString( ret ) ); return ret; } } if (from) { D_DEBUG_AT( SaWMan_Focus, " -> removing focus from %p\n", from ); evt.type = DWET_LOSTFOCUS; sawman_post_event( sawman, from, &evt ); if (sawman_window_border( from )) sawman_update_window( sawman, from, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); } if (to) { CoreWindow *window; CoreLayer *layer; window = to->window; D_MAGIC_ASSERT( window, CoreWindow ); layer = dfb_layer_at( window->stack->context->layer_id ); #ifndef OLD_COREWINDOWS_STRUCTURE if (window->toplevel) { CoreWindow *toplevel = window->toplevel; D_MAGIC_ASSERT( toplevel, CoreWindow ); toplevel->subfocus = window; } else if (window->subfocus) { window = window->subfocus; D_MAGIC_ASSERT( window, CoreWindow ); to = window->window_data; D_MAGIC_ASSERT( to, SaWManWindow ); } #endif evt.type = DWET_GOTFOCUS; sawman_post_event( sawman, to, &evt ); if (sawman_window_border( to )) sawman_update_window( sawman, to, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); /* Send notification to windows watchers */ dfb_wm_dispatch_WindowFocus( layer->core, to->window ); } sawman->focused_window = to; sawman->focused_window_switched = true; sawman->focused_window_to = to; return DFB_OK; } DirectResult sawman_post_event( SaWMan *sawman, SaWManWindow *sawwin, DFBWindowEvent *event ) { D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->window != NULL ); D_ASSERT( event != NULL ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); event->buttons = sawman->buttons; event->modifiers = sawman->modifiers; event->locks = sawman->locks; dfb_window_post_event( sawwin->window, event ); return DFB_OK; } DirectResult sawman_update_window( SaWMan *sawman, SaWManWindow *sawwin, const DFBRegion *region, DFBSurfaceFlipFlags flags, SaWManUpdateFlags update_flags ) { DFBRegion area; CoreWindowStack *stack; CoreWindow *window; SaWManTier *tier; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); DFB_REGION_ASSERT_IF( region ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); stack = sawwin->stack; window = sawwin->window; D_ASSERT( stack != NULL ); D_MAGIC_COREWINDOW_ASSERT( window ); D_DEBUG_AT( SaWMan_Update, "%s( %p, %p )\n", __FUNCTION__, sawwin, region ); if (!SAWMAN_VISIBLE_WINDOW(window) && !(update_flags & SWMUF_FORCE_INVISIBLE)) return DFB_OK; D_ASSUME( sawwin->flags & SWMWF_INSERTED ); /* Make sure window is inserted. */ if (!(sawwin->flags & SWMWF_INSERTED)) { D_DEBUG_AT( SaWMan_Update, " -> window %d not inserted!\n", window->id ); return DFB_OK; } tier = sawman_tier_by_class( sawman, window->config.stacking ); if (region) { if ((update_flags & SWMUF_SCALE_REGION) && (window->config.options & DWOP_SCALE)) { int sw = sawwin->src.w; int sh = sawwin->src.h; int dw = sawwin->dst.w; int dh = sawwin->dst.h; /* horizontal */ if (dw > sw) { /* upscaling */ area.x1 = (region->x1 - 1) * dw / sw; area.x2 = (region->x2 + 1) * dw / sw; } else { /* downscaling */ area.x1 = region->x1 * dw / sw - 1; area.x2 = region->x2 * dw / sw + 1; } /* vertical */ if (dh > sh) { /* upscaling */ area.y1 = (region->y1 - 1) * dh / sh; area.y2 = (region->y2 + 1) * dh / sh; } else { /* downscaling */ area.y1 = region->y1 * dh / sh - 1; area.y2 = region->y2 * dh / sh + 1; } /* limit to window area */ dfb_region_clip( &area, 0, 0, dw - 1, dh - 1 ); /* screen offset */ dfb_region_translate( &area, sawwin->dst.x, sawwin->dst.y ); } else area = DFB_REGION_INIT_TRANSLATED( region, sawwin->dst.x, sawwin->dst.y ); } else { if ((update_flags & SWMUF_UPDATE_BORDER) && sawman_window_border( sawwin )) area = DFB_REGION_INIT_FROM_RECTANGLE( &sawwin->bounds ); else area = DFB_REGION_INIT_FROM_RECTANGLE( &sawwin->dst ); } if (!dfb_unsafe_region_intersect( &area, 0, 0, tier->size.w - 1, tier->size.h - 1 )) return DFB_OK; if (update_flags & SWMUF_FORCE_COMPLETE) dfb_updates_add( &tier->updates, &area ); else wind_of_change( sawman, tier, &area, flags, fusion_vector_size( &sawman->layout ) - 1, sawman_window_index( sawman, sawwin ) ); return DFB_OK; } DirectResult sawman_showing_window( SaWMan *sawman, SaWManWindow *sawwin, bool *ret_showing ) { DFBRegion area; CoreWindowStack *stack; CoreWindow *window; SaWManTier *tier; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); stack = sawwin->stack; window = sawwin->window; D_ASSERT( stack != NULL ); D_MAGIC_COREWINDOW_ASSERT( window ); if (!sawman_tier_by_stack( sawman, stack, &tier )) return DFB_BUG; *ret_showing = false; if (!SAWMAN_VISIBLE_WINDOW(window)) return DFB_OK; /* Make sure window is inserted. */ if (!(sawwin->flags & SWMWF_INSERTED)) return DFB_OK; area = DFB_REGION_INIT_FROM_RECTANGLE( &sawwin->bounds ); if (!dfb_unsafe_region_intersect( &area, 0, 0, stack->width - 1, stack->height - 1 )) return DFB_OK; if (fusion_vector_has_elements( &sawman->layout ) && window >= 0) { int num = fusion_vector_size( &sawman->layout ); wind_of_showing( sawman, tier, &area, num - 1, sawman_window_index( sawman, sawwin ), ret_showing ); } else *ret_showing = true; return DFB_OK; } DirectResult sawman_insert_window( SaWMan *sawman, SaWManWindow *sawwin, SaWManWindow *relative, bool top ) { DirectResult ret; int index = 0; SaWManWindow *other; CoreWindow *window; CoreLayer *layer; D_DEBUG_AT( SaWMan_Stacking, "%s( %p, %p, %p, %s )\n", __FUNCTION__, sawman, sawwin, relative, top ? "top" : "below" ); D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_MAGIC_ASSERT_IF( relative, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); layer = dfb_layer_at( window->stack->context->layer_id ); #ifndef OLD_COREWINDOWS_STRUCTURE /* In case of a sub window, the order from sub window vector is followed */ if (window->toplevel) { CoreWindow *toplevel = window->toplevel; CoreWindow *tmp; SaWManWindow *parent; /* Enforce association rules... */ parent = sawwin->parent; if (parent) { D_MAGIC_ASSERT( parent, SaWManWindow ); tmp = parent->window; D_ASSERT( tmp != NULL ); D_ASSERT( tmp->toplevel == toplevel ); if (window->config.options & DWOP_KEEP_UNDER) { int under; index = fusion_vector_index_of( &toplevel->subwindows, window ); under = fusion_vector_index_of( &toplevel->subwindows, parent ); if (index < under - 1) { D_DEBUG_AT( SaWMan_Stacking, " -> moving under (%d->%d)\n", index, under - 1 ); fusion_vector_move( &toplevel->subwindows, index, under - 1 ); } else if (index > under - 1) { D_DEBUG_AT( SaWMan_Stacking, " -> moving under (%d<-%d)\n", under, index ); fusion_vector_move( &toplevel->subwindows, index, under ); } } else if (window->config.options & DWOP_KEEP_ABOVE) { int above; index = fusion_vector_index_of( &toplevel->subwindows, window ); above = fusion_vector_index_of( &toplevel->subwindows, parent ); if (index < above + 1) { D_DEBUG_AT( SaWMan_Stacking, " -> moving above (%d->%d)\n", index, above ); fusion_vector_move( &toplevel->subwindows, index, above ); } else if (index > above + 1) { D_DEBUG_AT( SaWMan_Stacking, " -> moving above (%d<-%d)\n", above + 1, index ); fusion_vector_move( &toplevel->subwindows, index, above + 1 ); } } } /* Lookup our index in top level window */ index = fusion_vector_index_of( &toplevel->subwindows, window ); D_DEBUG_AT( SaWMan_Stacking, " -> toplevel %p [%4d,%4d-%4dx%4d] (%d)\n", toplevel, DFB_RECTANGLE_VALS(&toplevel->config.bounds), index ); /* Get sub window below (or top level) */ if (index == 0) tmp = toplevel; else tmp = fusion_vector_at( &toplevel->subwindows, index - 1 ); D_DEBUG_AT( SaWMan_Stacking, " -> relative %p [%4d,%4d-%4dx%4d] (%d)\n", tmp, DFB_RECTANGLE_VALS(&tmp->config.bounds), index - 1 ); /* Place on top */ relative = tmp->window_data; top = true; } else #endif if (sawwin->parent && (window->config.options & (DWOP_KEEP_ABOVE|DWOP_KEEP_UNDER))) { D_MAGIC_ASSERT( sawwin->parent, SaWManWindow ); relative = sawwin->parent; top = (window->config.options & DWOP_KEEP_ABOVE) ? true : false; D_MAGIC_ASSERT( relative, SaWManWindow ); #ifndef OLD_COREWINDOWS_STRUCTURE if (top && relative->window->subwindows.count) { CoreWindow *tmp; tmp = fusion_vector_at( &relative->window->subwindows, relative->window->subwindows.count - 1 ); relative = tmp->window_data; D_MAGIC_ASSERT( relative, SaWManWindow ); } #endif } if (relative) D_ASSUME( relative->priority == sawwin->priority ); if (relative) { index = sawman_window_index( sawman, relative ); D_ASSERT( index >= 0 ); D_ASSERT( index < sawman->layout.count ); if (top) index++; } else if (top) { /* * Iterate from bottom to top, * stopping at the first window with a higher priority. */ fusion_vector_foreach (other, index, sawman->layout) { D_MAGIC_ASSERT( other, SaWManWindow ); if (other->priority > sawwin->priority) break; } } else { /* * Iterate from bottom to top, * stopping at the first window with equal or higher priority. */ fusion_vector_foreach (other, index, sawman->layout) { D_MAGIC_ASSERT( other, SaWManWindow ); if (other->priority >= sawwin->priority) break; } } /* (Re)Insert the window at the acquired position. */ if (sawwin->flags & SWMWF_INSERTED) { int old = sawman_window_index( sawman, sawwin ); D_ASSERT( old >= 0 ); D_ASSERT( old < sawman->layout.count ); if (old < index) index--; if (old != index) { fusion_vector_move( &sawman->layout, old, index ); dfb_wm_dispatch_WindowRestack( layer->core, window, index ); } } else { ret = fusion_vector_insert( &sawman->layout, sawwin, index ); if (ret) return ret; dfb_wm_dispatch_WindowRestack( layer->core, window, index ); /* Set 'inserted' flag. */ sawwin->flags |= SWMWF_INSERTED; window->flags |= CWF_INSERTED; dfb_wm_dispatch_WindowState( layer->core, window ); } return DFB_OK; } DirectResult sawman_remove_window( SaWMan *sawman, SaWManWindow *sawwin ) { int index; CoreWindow *window; SaWManGrabbedKey *key; DirectLink *next; CoreLayer *layer; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); layer = dfb_layer_at( window->stack->context->layer_id ); if (!(sawwin->flags & SWMWF_INSERTED)) { D_BUG( "window %d not inserted", window->id ); return DFB_BUG; } sawman_withdraw_window( sawman, sawwin ); index = sawman_window_index( sawman, sawwin ); D_ASSERT( index >= 0 ); D_ASSERT( index < sawman->layout.count ); fusion_vector_remove( &sawman->layout, index ); /* Release all explicit key grabs. */ direct_list_foreach_safe (key, next, sawman->grabbed_keys) { if (key->owner == sawwin) { direct_list_remove( &sawman->grabbed_keys, &key->link ); SHFREE( sawwin->shmpool, key ); } } /* Release grab of unselected keys. */ if (sawman->unselkeys_window == sawwin) sawman->unselkeys_window = NULL; /* Free key list. */ if (window->config.keys) { SHFREE( sawwin->shmpool, window->config.keys ); window->config.keys = NULL; window->config.num_keys = 0; } sawwin->flags &= ~SWMWF_INSERTED; window->flags &= ~CWF_INSERTED; dfb_wm_dispatch_WindowState( layer->core, window ); return DFB_OK; } DirectResult sawman_withdraw_window( SaWMan *sawman, SaWManWindow *sawwin ) { int i, index; CoreWindow *window; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); /* Make sure window is inserted. */ // NDC - remove the if // if (!(sawwin->flags & SWMWF_INSERTED)) { // D_BUG( "window %d not inserted", window->id ); // } /* No longer be the 'entered window'. */ if (sawman->entered_window == sawwin) sawman->entered_window = NULL; if (sawman->focused_window_to == sawwin) { sawman->focused_window_to = NULL; sawman->focused_window_switched = false; } /* Remove focus from window. */ if (sawman->focused_window == sawwin) { SaWManWindow *swin; CoreWindow *cwin; sawman_switch_focus( sawman, NULL ); // sawman->focused_window = NULL; /* Always try to have a focused window */ fusion_vector_foreach_reverse (swin, index, sawman->layout) { D_MAGIC_ASSERT( swin, SaWManWindow ); cwin = swin->window; D_ASSERT( cwin != NULL ); if (swin != sawwin && cwin->config.opacity && !(cwin->config.options & DWOP_GHOST)) { sawman_switch_focus( sawman, swin ); break; } } } #ifndef OLD_COREWINDOWS_STRUCTURE if (window->toplevel) { CoreWindow *toplevel = window->toplevel; D_MAGIC_ASSERT( toplevel, CoreWindow ); if (toplevel->subfocus == window) toplevel->subfocus = NULL; } #endif /* Release explicit keyboard grab. */ if (sawman->keyboard_window == sawwin) sawman->keyboard_window = NULL; /* Release explicit pointer grab. */ if (sawman->pointer_window == sawwin) sawman->pointer_window = NULL; /* Release all implicit key grabs. */ for (i=0; ikeys[i].code != -1 && sawman->keys[i].owner == sawwin) { if (!DFB_WINDOW_DESTROYED( window )) { DFBWindowEvent we; we.type = DWET_KEYUP; we.key_code = sawman->keys[i].code; we.key_id = sawman->keys[i].id; we.key_symbol = sawman->keys[i].symbol; sawman_post_event( sawman, sawwin, &we ); } sawman->keys[i].code = -1; sawman->keys[i].owner = NULL; } } /* Hide window. */ // NDC but don't for SWMWF_INSERTED windows if ((sawwin->flags & SWMWF_INSERTED)) { if (SAWMAN_VISIBLE_WINDOW(window)) { window->config.opacity = 0; sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_FORCE_INVISIBLE | SWMUF_UPDATE_BORDER ); } } return DFB_OK; } static void apply_geometry( const DFBWindowGeometry *geometry, const DFBRegion *clip, const DFBWindowGeometry *parent, DFBRectangle *ret_rect ) { int width, height; D_ASSERT( geometry != NULL ); DFB_REGION_ASSERT( clip ); D_ASSERT( ret_rect != NULL ); width = clip->x2 - clip->x1 + 1; height = clip->y2 - clip->y1 + 1; switch (geometry->mode) { case DWGM_DEFAULT: D_DEBUG_AT( SaWMan_Geometry, " -- default\n" ); *ret_rect = DFB_RECTANGLE_INIT_FROM_REGION( clip ); D_DEBUG_AT( SaWMan_Geometry, " => %d,%d-%dx%d\n", DFB_RECTANGLE_VALS( ret_rect ) ); return; case DWGM_FOLLOW: D_ASSERT( parent != NULL ); D_DEBUG_AT( SaWMan_Geometry, " -- FOLLOW\n" ); apply_geometry( parent, clip, NULL, ret_rect ); break; case DWGM_RECTANGLE: D_DEBUG_AT( SaWMan_Geometry, " -- RECTANGLE [%d,%d-%dx%d]\n", DFB_RECTANGLE_VALS( &geometry->rectangle ) ); *ret_rect = geometry->rectangle; ret_rect->x += clip->x1; ret_rect->y += clip->y1; break; case DWGM_LOCATION: D_DEBUG_AT( SaWMan_Geometry, " -- LOCATION [%.3f,%.3f-%.3fx%.3f]\n", geometry->location.x, geometry->location.y, geometry->location.w, geometry->location.h ); ret_rect->x = (int)(geometry->location.x * width + 0.5f) + clip->x1; ret_rect->y = (int)(geometry->location.y * height + 0.5f) + clip->y1; ret_rect->w = (int)(geometry->location.w * width + 0.5f); ret_rect->h = (int)(geometry->location.h * height + 0.5f); break; default: D_BUG( "invalid geometry mode %d", geometry->mode ); return; } D_DEBUG_AT( SaWMan_Geometry, " -> %d,%d-%dx%d / clip [%d,%d-%dx%d]\n", DFB_RECTANGLE_VALS( ret_rect ), DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); if (!dfb_rectangle_intersect_by_region( ret_rect, clip )) { D_WARN( "invalid geometry" ); dfb_rectangle_from_region( ret_rect, clip ); } D_DEBUG_AT( SaWMan_Geometry, " => %d,%d-%dx%d\n", DFB_RECTANGLE_VALS( ret_rect ) ); } DirectResult sawman_update_geometry( SaWManWindow *sawwin ) { int i; CoreWindow *window; CoreWindow *parent_window = NULL; CoreWindow *toplevel; SaWManWindow *topsaw = NULL; SaWMan *sawman; SaWManWindow *parent; SaWManWindow *child; CoreWindow *childwin; DFBRegion clip; DFBRectangle src; DFBRectangle dst; bool src_updated = false; bool dst_updated = false; D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_DEBUG_AT( SaWMan_Geometry, "%s( %p )\n", __FUNCTION__, sawwin ); sawman = sawwin->sawman; D_MAGIC_ASSERT_IF( sawman, SaWMan ); if (sawman) FUSION_SKIRMISH_ASSERT( &sawman->lock ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); parent = sawwin->parent; if (parent) { D_MAGIC_ASSERT( parent, SaWManWindow ); parent_window = parent->window; D_ASSERT( parent_window != NULL ); } toplevel = WINDOW_TOPLEVEL(window); if (toplevel) { topsaw = toplevel->window_data; D_MAGIC_ASSERT( topsaw, SaWManWindow ); } if (parent && (window->config.options & DWOP_FOLLOW_BOUNDS)) /* Initialize bounds from parent window (window association) */ sawwin->bounds = parent->bounds; else /* Initialize bounds from base window configuration */ sawwin->bounds = window->config.bounds; /* * In case of a sub window, the top level surface is the coordinate space instead of the layer surface */ toplevel = WINDOW_TOPLEVEL(window); if (toplevel) { DFBDimension in, out; D_DEBUG_AT( SaWMan_Geometry, " -> sub bounds %4d,%4d-%4dx%4d (base)\n", DFB_RECTANGLE_VALS(&sawwin->bounds) ); D_DEBUG_AT( SaWMan_Geometry, " o- top src %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS(&topsaw->src) ); D_DEBUG_AT( SaWMan_Geometry, " o- top dst %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS(&topsaw->dst) ); /* * Translate against top level source geometry */ sawwin->bounds.x -= topsaw->src.x; sawwin->bounds.y -= topsaw->src.y; D_DEBUG_AT( SaWMan_Geometry, " -> sub bounds %4d,%4d-%4dx%4d (translated)\n", DFB_RECTANGLE_VALS(&sawwin->bounds) ); /* * Take input dimension from top level source geometry */ in.w = topsaw->src.w; in.h = topsaw->src.h; /* * Take output dimension from top level destination geometry */ out.w = topsaw->dst.w; out.h = topsaw->dst.h; /* * Scale the sub window size if top level window is scaled */ if (in.w != out.w || in.h != out.h) { D_DEBUG_AT( SaWMan_Geometry, " o- scale in %4dx%4d\n", in.w, in.h ); D_DEBUG_AT( SaWMan_Geometry, " o- scale out %4dx%4d\n", out.w, out.h ); sawwin->bounds.x = sawwin->bounds.x * out.w / in.w; sawwin->bounds.y = sawwin->bounds.y * out.h / in.h; sawwin->bounds.w = sawwin->bounds.w * out.w / in.w; sawwin->bounds.h = sawwin->bounds.h * out.h / in.h; D_DEBUG_AT( SaWMan_Geometry, " -> sub bounds %4d,%4d-%4dx%4d (scaled)\n", DFB_RECTANGLE_VALS(&sawwin->bounds) ); } /* * Translate to top level destination geometry */ sawwin->bounds.x += topsaw->dst.x; sawwin->bounds.y += topsaw->dst.y; D_DEBUG_AT( SaWMan_Geometry, " => sub bounds %4d,%4d-%4dx%4d (translated)\n", DFB_RECTANGLE_VALS(&sawwin->bounds) ); } /* Calculate source geometry. */ clip.x1 = 0; clip.y1 = 0; if ( (window->caps & (DWCAPS_INPUTONLY | DWCAPS_COLOR)) || window->config.options & DWOP_INPUTONLY ) { clip.x2 = sawwin->bounds.w - 1; clip.y2 = sawwin->bounds.h - 1; } else { CoreSurface *surface = window->surface; D_ASSERT( surface != NULL ); clip.x2 = surface->config.size.w - 1; clip.y2 = surface->config.size.h - 1; } D_DEBUG_AT( SaWMan_Geometry, " -> Applying source geometry...\n" ); apply_geometry( &window->config.src_geometry, &clip, parent_window ? &parent_window->config.src_geometry : NULL, &src ); /* Calculate destination geometry. */ clip = DFB_REGION_INIT_FROM_RECTANGLE( &sawwin->bounds ); D_DEBUG_AT( SaWMan_Geometry, " -> Applying destination geometry...\n" ); apply_geometry( &window->config.dst_geometry, &clip, parent_window ? &parent_window->config.dst_geometry : NULL, &dst ); /* Adjust src/dst if clipped by top level window */ if (toplevel) { DFBRegion topclip = DFB_REGION_INIT_FROM_RECTANGLE( &topsaw->dst ); /* * Clip the sub window bounds against the top level window */ dfb_clip_stretchblit( &topclip, &src, &dst ); D_DEBUG_AT( SaWMan_Geometry, " => sub dst %4d,%4d-%4dx%4d (clipped)\n", DFB_RECTANGLE_VALS(&dst) ); D_DEBUG_AT( SaWMan_Geometry, " => sub src %4d,%4d-%4dx%4d (clipped)\n", DFB_RECTANGLE_VALS(&src) ); } /* Update source geometry. */ if (!DFB_RECTANGLE_EQUAL( src, sawwin->src )) { sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_NONE ); sawwin->src = src; src_updated = true; } /* Update destination geometry. */ if (!DFB_RECTANGLE_EQUAL( dst, sawwin->dst )) { if (!src_updated) sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_NONE ); sawwin->dst = dst; dst_updated = true; sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_NONE ); } D_DEBUG_AT( SaWMan_Geometry, " -> Updating children (associated windows)...\n" ); fusion_vector_foreach (child, i, sawwin->children) { D_MAGIC_ASSERT( child, SaWManWindow ); childwin = child->window; D_ASSERT( childwin != NULL ); if ((childwin->config.src_geometry.mode == DWGM_FOLLOW && src_updated) || (childwin->config.dst_geometry.mode == DWGM_FOLLOW && dst_updated) || (childwin->config.options & DWOP_FOLLOW_BOUNDS)) sawman_update_geometry( child ); } #ifndef OLD_COREWINDOWS_STRUCTURE D_DEBUG_AT( SaWMan_Geometry, " -> Updating children (sub windows)...\n" ); fusion_vector_foreach (childwin, i, window->subwindows) { D_ASSERT( childwin != NULL ); sawman_update_geometry( childwin->window_data ); } #endif return DFB_OK; } DirectResult sawman_set_opacity( SaWMan *sawman, SaWManWindow *sawwin, u8 opacity ) { u8 old; StackData *data; CoreWindowStack *stack; CoreWindow *window; D_DEBUG_AT( SaWMan_Focus, "%s( %p, sawwin %p, opacity 0x%02x )\n", __FUNCTION__, sawman, sawwin, opacity ); D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->stack_data != NULL ); D_ASSERT( sawwin->stack != NULL ); D_ASSERT( sawwin->window != NULL ); data = sawwin->stack_data; stack = sawwin->stack; window = sawwin->window; old = window->config.opacity; if (!dfb_config->translucent_windows && opacity) { D_DEBUG_AT( SaWMan_Focus, " -> forcing to 0xff\n" ); opacity = 0xFF; } if (old != opacity) { window->config.opacity = opacity; if (sawwin->flags & SWMWF_INSERTED) { sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_FORCE_INVISIBLE | SWMUF_UPDATE_BORDER ); /* Ungrab pointer/keyboard, pass focus... */ if (old && !opacity) { D_DEBUG_AT( SaWMan_Focus, " -> hiding window... (focused %p)\n", sawman->focused_window ); /* Possibly switch focus to window now under the cursor */ if (sawman->focused_window == sawwin) { D_DEBUG_AT( SaWMan_Focus, " -> updating focus\n" ); sawman_update_focus( data->sawman, data->stack, data->stack->cursor.x, data->stack->cursor.y ); } D_DEBUG_AT( SaWMan_Focus, " -> withdrawing window...\n" ); sawman_withdraw_window( sawman, sawwin ); } } else D_DEBUG_AT( SaWMan_Focus, " -> not inserted\n" ); } else D_DEBUG_AT( SaWMan_Focus, " -> no change\n" ); return DFB_OK; } DirectResult sawman_window_set_cursor_flags( SaWMan *sawman, SaWManWindow *sawwin, DFBWindowCursorFlags flags ) { StackData *data; CoreWindowStack *stack; CoreWindow *window; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->stack_data != NULL ); D_ASSERT( sawwin->stack != NULL ); D_ASSERT( sawwin->window != NULL ); data = sawwin->stack_data; stack = sawwin->stack; window = sawwin->window; if (window->config.cursor_flags != flags) { window->config.cursor_flags = flags; if (sawwin == sawman->focused_window) sawman_window_apply_cursor_flags( sawman, sawwin ); } return DFB_OK; } DirectResult sawman_window_apply_cursor_flags( SaWMan *sawman, SaWManWindow *sawwin ) { StackData *data; CoreWindowStack *stack; CoreWindow *window; CoreCursorUpdateFlags update = CCUF_NONE; u8 opacity; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->stack_data != NULL ); D_ASSERT( sawwin->stack != NULL ); D_ASSERT( sawwin->window != NULL ); data = sawwin->stack_data; stack = sawwin->stack; window = sawwin->window; D_DEBUG_AT( SaWMan_Cursor, "%s( %p, flags 0x%04x )\n", __FUNCTION__, sawwin, window->config.cursor_flags ); opacity = (window->config.cursor_flags & DWCF_INVISIBLE) ? 0x00 : 0xff; D_DEBUG_AT( SaWMan_Cursor, " -> opacity %d\n", opacity ); if (!(window->config.cursor_flags & DWCF_UNCLIPPED)) { int cx = stack->cursor.x; int cy = stack->cursor.y; if (cx < 0) cx = 0; else if (cx >= sawman->resolution.w) cx = sawman->resolution.w - 1; if (cy < 0) cy = 0; else if (cy >= sawman->resolution.h) cy = sawman->resolution.h - 1; if (cx != stack->cursor.x || cy != stack->cursor.y) { D_DEBUG_AT( SaWMan_Cursor, " -> Cursor clipped %d,%d -> %d,%d\n", stack->cursor.x, stack->cursor.y, cx, cy ); printf( "===JK sawman -> Cursor clipped %d,%d -> %d,%d\n", stack->cursor.x, stack->cursor.y, cx, cy ); stack->cursor.x = cx; stack->cursor.y = cy; update |= CCUF_POSITION; } } if (stack->cursor.opacity != opacity) { stack->cursor.opacity = opacity; update |= CCUF_OPACITY; } D_DEBUG_AT( SaWMan_Cursor, " -> update 0x%04x\n", update ); if (update) dfb_wm_update_cursor( stack, update ); return DFB_OK; } bool sawman_update_focus( SaWMan *sawman, CoreWindowStack *stack, int x, int y ) { StackData *data; D_DEBUG_AT( SaWMan_Focus, "%s( %p, stack %p, xy %d,%d )\n", __FUNCTION__, sawman, stack, x, y ); D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( stack != NULL ); data = stack->stack_data; D_MAGIC_ASSERT( data, StackData ); /* if pointer is not grabbed */ if (!sawman->pointer_window) { SaWManWindow *before = sawman->entered_window; SaWManWindow *after = sawman_window_at_pointer( sawman, stack, x, y ); /* and the window under the cursor is another one now */ if (before != after) { DFBWindowEvent we; /* send leave event */ if (before) { D_MAGIC_ASSERT( before, SaWManWindow ); D_ASSERT( before->window != NULL ); we.type = DWET_LEAVE; sawman_window_get_cursor_position( sawman, stack, before, &we.x, &we.y, &we.cx, &we.cy ); sawman_post_event( sawman, before, &we ); } /* switch focus and send enter event */ sawman_switch_focus( sawman, after ); if (after) { D_MAGIC_ASSERT( after, SaWManWindow ); D_ASSERT( after->window != NULL ); we.type = DWET_ENTER; sawman_window_get_cursor_position( sawman, stack, after, &we.x, &we.y, &we.cx, &we.cy ); sawman_post_event( sawman, after, &we ); } /* update pointer to window under the cursor */ sawman->entered_window = after; return true; } } return false; } DFBResult sawman_restack_window( SaWMan *sawman, SaWManWindow *sawwin, SaWManWindow *relative, int relation, DFBWindowStackingClass stacking ) { int i; int old; int index; int priority; StackData *data; SaWManWindow *tmpsaw; CoreWindow *window; CoreLayer *layer; #ifndef OLD_COREWINDOWS_STRUCTURE int n; CoreWindow *tmp; #endif D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_MAGIC_ASSERT_IF( relative, SaWManWindow ); D_ASSERT( sawwin->stack_data != NULL ); D_ASSERT( relative == NULL || relative == sawwin || relation != 0); D_DEBUG_AT( SaWMan_Stacking, "%s( %p, %p, %p, %d, 0x%d )\n", __FUNCTION__, sawman, sawwin, relative, relation, stacking ); data = sawwin->stack_data; window = sawwin->window; D_ASSERT( window != NULL ); layer = dfb_layer_at( window->stack->context->layer_id ); /* Change stacking class. */ if (stacking != window->config.stacking) { window->config.stacking = stacking; sawwin->priority = sawman_window_priority( sawwin ); } /* Make sure window is inserted and not kept above/under parent. */ if (!(sawwin->flags & SWMWF_INSERTED) || (window->config.options & (DWOP_KEEP_ABOVE|DWOP_KEEP_UNDER))) return DFB_OK; /* Get the (new) priority. */ priority = sawwin->priority; #ifndef OLD_COREWINDOWS_STRUCTURE /* In case of a sub window, the sub window vector is modified and the window reinserted */ if (window->toplevel) { CoreWindow *toplevel = window->toplevel; /* Get the old index. */ old = fusion_vector_index_of( &toplevel->subwindows, window ); D_ASSERT( old >= 0 ); D_DEBUG_AT( SaWMan_Stacking, " -> old sub index %d\n", old ); /* Calculate the desired index. */ if (relative) { index = fusion_vector_index_of( &toplevel->subwindows, relative->window ); if (index < 0) return DFB_INVARG; if (relation > 0) { if (old < index) index--; } else if (relation < 0) { if (old > index) index++; } index += relation; if (index < 0) index = 0; else if (index > toplevel->subwindows.count - 1) index = toplevel->subwindows.count - 1; } else if (relation) index = toplevel->subwindows.count - 1; else index = 0; D_DEBUG_AT( SaWMan_Stacking, " -> new sub index %d\n", index ); if (relation < 0) { while (index > 0) { SaWManWindow *other = fusion_vector_at( &toplevel->subwindows, index ); SaWManWindow *under = fusion_vector_at( &toplevel->subwindows, index - 1 ); D_MAGIC_ASSERT( other, SaWManWindow ); D_MAGIC_ASSERT( under, SaWManWindow ); if ((other->window->config.options & DWOP_KEEP_ABOVE) || (under->window->config.options & DWOP_KEEP_UNDER)) index--; else break; } } else if (relation > 0) { while (index < toplevel->subwindows.count - 1) { SaWManWindow *other = fusion_vector_at( &toplevel->subwindows, index ); SaWManWindow *above = fusion_vector_at( &toplevel->subwindows, index + 1 ); D_MAGIC_ASSERT( other, SaWManWindow ); D_MAGIC_ASSERT( above, SaWManWindow ); if ((above->window->config.options & DWOP_KEEP_ABOVE) || (other->window->config.options & DWOP_KEEP_UNDER)) index++; else break; } } D_DEBUG_AT( SaWMan_Stacking, " -> new sub index %d\n", index ); /* Return if index hasn't changed. */ if (index == old) return DFB_OK; sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); /* Actually change the stacking order now. */ fusion_vector_move( &toplevel->subwindows, old, index ); /* Reinsert to move in layout as well. */ sawman_insert_window( sawman, sawwin, NULL, false ); /* Reinsert associated windows to ensure above/under rules apply. */ fusion_vector_foreach (tmpsaw, i, sawwin->children) { if (tmpsaw->window->config.options & (DWOP_KEEP_ABOVE|DWOP_KEEP_UNDER)) { sawman_update_window( sawman, tmpsaw, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); sawman_insert_window( sawman, tmpsaw, NULL, false ); sawman_update_window( sawman, tmpsaw, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); } } } else #endif { /* Get the old index. */ old = sawman_window_index( sawman, sawwin ); D_ASSERT( old >= 0 ); D_DEBUG_AT( SaWMan_Stacking, " -> old index %d\n", old ); /* Calculate the desired index. */ if (relative) { index = sawman_window_index( sawman, relative ); if (relation > 0) { if (old < index) index--; } else if (relation < 0) { if (old > index) index++; } index += relation; if (relation > 0) index += WINDOW_SUBWINDOWS_COUNT(window); if (index < 0) index = 0; else if (index > sawman->layout.count - 1) index = sawman->layout.count - 1; } else if (relation) index = sawman->layout.count - 1; else index = 0; D_DEBUG_AT( SaWMan_Stacking, " -> new index %d\n", index ); /* Assure window won't be above any window with a higher priority. */ while (index > 0) { int below = (old < index) ? index : index - 1; SaWManWindow *other = fusion_vector_at( &sawman->layout, below ); D_MAGIC_ASSERT( other, SaWManWindow ); if (priority < other->priority) index--; else break; } D_DEBUG_AT( SaWMan_Stacking, " -> new index %d\n", index ); /* Assure window won't be below any window with a lower priority. */ while (index < sawman->layout.count - 1) { int above = (old > index) ? index : index + 1; SaWManWindow *other = fusion_vector_at( &sawman->layout, above ); D_MAGIC_ASSERT( other, SaWManWindow ); if (priority > other->priority) index++; else break; } D_DEBUG_AT( SaWMan_Stacking, " -> new index %d\n", index ); if (relation < 0) { /* Assure window won't be below a sub window (getting between sub and top or other sub window) */ while (index > 0) { SaWManWindow *other = fusion_vector_at( &sawman->layout, index ); SaWManWindow *under = fusion_vector_at( &sawman->layout, index - 1 ); D_MAGIC_ASSERT( other, SaWManWindow ); D_MAGIC_ASSERT( under, SaWManWindow ); if (WINDOW_TOPLEVEL(other->window) || (other->window->config.options & DWOP_KEEP_ABOVE) || (under->window->config.options & DWOP_KEEP_UNDER)) index--; else break; } } else if (relation > 0) { /* Assure window won't be below a sub window (getting between sub and top or other sub window) */ while (index < sawman->layout.count - 1) { SaWManWindow *other = fusion_vector_at( &sawman->layout, index ); SaWManWindow *above = fusion_vector_at( &sawman->layout, index + 1 ); D_MAGIC_ASSERT( other, SaWManWindow ); D_MAGIC_ASSERT( above, SaWManWindow ); if (WINDOW_TOPLEVEL(above->window) || (above->window->config.options & DWOP_KEEP_ABOVE) || (other->window->config.options & DWOP_KEEP_UNDER)) index++; else break; } } D_DEBUG_AT( SaWMan_Stacking, " -> new index %d\n", index ); /* Return if index hasn't changed. */ if (index == old) return DFB_OK; sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); /* Actually change the stacking order now. */ fusion_vector_move( &sawman->layout, old, index ); D_DEBUG_AT( SaWMan_Stacking, " -> now index %d\n", fusion_vector_index_of( &sawman->layout, sawwin ) ); dfb_wm_dispatch_WindowRestack( layer->core, window, index ); #ifndef OLD_COREWINDOWS_STRUCTURE /* Reinsert sub windows to ensure they're in order (above top level). */ fusion_vector_foreach (tmp, i, window->subwindows) { sawman_update_window( sawman, tmp->window_data, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); sawman_insert_window( sawman, tmp->window_data, NULL, false ); sawman_update_window( sawman, tmp->window_data, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); } #endif /* Reinsert associated windows to ensure above/under rules apply. */ fusion_vector_foreach (tmpsaw, i, sawwin->children) { if (tmpsaw->window->config.options & (DWOP_KEEP_ABOVE|DWOP_KEEP_UNDER)) { sawman_update_window( sawman, tmpsaw, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); sawman_insert_window( sawman, tmpsaw, NULL, false ); sawman_update_window( sawman, tmpsaw, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); #ifndef OLD_COREWINDOWS_STRUCTURE /* Reinsert sub windows to ensure they're in order (above top level). */ fusion_vector_foreach (tmp, n, tmpsaw->window->subwindows) { sawman_update_window( sawman, tmp->window_data, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); sawman_insert_window( sawman, tmp->window_data, NULL, false ); sawman_update_window( sawman, tmp->window_data, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); } #endif } } } sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER ); return DFB_OK; } SaWManWindow* sawman_window_at_pointer( SaWMan *sawman, CoreWindowStack *stack, int x, int y ) { int i; SaWManWindow *sawwin; CoreWindow *window; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( stack != NULL ); if (!stack->cursor.enabled) { fusion_vector_foreach_reverse (sawwin, i, sawman->layout) { D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_ASSERT( window != NULL ); if (window->config.opacity && !(window->config.options & DWOP_GHOST)) return sawwin; } return NULL; } if (x < 0) x = stack->cursor.x; if (y < 0) y = stack->cursor.y; fusion_vector_foreach_reverse (sawwin, i, sawman->layout) { SaWManTier *tier; int tx, ty; D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_ASSERT( window != NULL ); /* Retrieve corresponding SaWManTier. */ tier = sawman_tier_by_class( sawman, sawwin->window->config.stacking ); D_MAGIC_ASSERT( tier, SaWManTier ); /* Convert to Tier coordinates */ tx = (s64) x * (s64) tier->size.w / (s64) sawman->resolution.w; ty = (s64) y * (s64) tier->size.h / (s64) sawman->resolution.h; if (!(window->config.options & DWOP_GHOST) && window->config.opacity && tx >= sawwin->bounds.x && tx < sawwin->bounds.x + sawwin->bounds.w && ty >= sawwin->bounds.y && ty < sawwin->bounds.y + sawwin->bounds.h) return sawwin; } return NULL; } void sawman_window_get_cursor_position( SaWMan *sawman, CoreWindowStack *stack, SaWManWindow *sawwin, int *ret_x, int *ret_y, int *ret_cx, int *ret_cy ) { int x, y; int cx, cy; int sx, sy; SaWManTier *tier; D_MAGIC_ASSERT( sawman, SaWMan ); D_ASSERT( stack != NULL ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_ASSERT( sawwin->window != NULL ); /* Retrieve corresponding SaWManTier. */ tier = sawman_tier_by_class( sawman, sawwin->window->config.stacking ); D_MAGIC_ASSERT( tier, SaWManTier ); x = stack->cursor.x; y = stack->cursor.y; /* Convert to Tier coordinates */ cx = (s64) x * (s64) tier->size.w / (s64) sawman->resolution.w; cy = (s64) y * (s64) tier->size.h / (s64) sawman->resolution.h; /* Subtract offset of Window within layout (tier coordinates) */ x = cx - sawwin->dst.x; y = cy - sawwin->dst.y; /* Convert to Window coordinates */ sx = sawwin->window->config.cursor_resolution.w ?: sawwin->src.w; sy = sawwin->window->config.cursor_resolution.h ?: sawwin->src.h; x = x * sx / sawwin->dst.w; y = y * sy / sawwin->dst.h; cx = cx * sx / sawwin->dst.w; cy = cy * sy / sawwin->dst.h; if (ret_x) *ret_x = x; if (ret_y) *ret_y = y; if (ret_cx) *ret_cx = cx; if (ret_cy) *ret_cy = cy; D_INFO( "%d,%d - %d,%d\n",x,y,cx,cy); } int sawman_window_border( const SaWManWindow *sawwin ) { SaWMan *sawman; const CoreWindow *window; const SaWManTier *tier; const SaWManBorderInit *border; int thickness = 0; D_MAGIC_ASSERT( sawwin, SaWManWindow ); sawman = sawwin->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); if (sawwin->caps & DWCAPS_NODECORATION) return 0; window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); tier = sawman_tier_by_class( sawwin->sawman, window->config.stacking ); D_MAGIC_ASSERT( tier, SaWManTier ); D_ASSERT( sawman_config != NULL ); border = &sawman_config->borders[sawman_window_priority(sawwin)]; thickness = border->thickness; if (thickness && border->resolution.w && border->resolution.h) { if (border->resolution.w != tier->size.w && border->resolution.h != tier->size.h) { int tw = thickness * tier->size.w / border->resolution.w; int th = thickness * tier->size.h / border->resolution.h; thickness = (tw + th + 1) / 2; } } return thickness; } /**********************************************************************************************************************/ /* skipping opaque windows that are above the window that changed */ static void wind_of_change( SaWMan *sawman, SaWManTier *tier, DFBRegion *update, DFBSurfaceFlipFlags flags, int current, int changed ) { D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); D_ASSERT( update != NULL ); /* loop through windows above */ for (; current > changed; current--) { CoreWindow *window; SaWManWindow *sawwin; DFBRegion opaque; DFBWindowOptions options; D_ASSERT( changed >= 0 ); D_ASSERT( current >= changed ); D_ASSERT( current < fusion_vector_size( &sawman->layout ) ); sawwin = fusion_vector_at( &sawman->layout, current ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); options = window->config.options; D_DEBUG_AT( SaWMan_Update, "--[%p] %4d,%4d-%4dx%4d : %d->%d\n", tier, DFB_RECTANGLE_VALS_FROM_REGION( update ), current, changed ); /* can skip opaque region */ if ((tier->classes & (1 << window->config.stacking)) && ( ( //can skip all opaque window? (window->config.opacity == 0xff) && !(window->caps & DWCAPS_INPUTONLY) && !(options & (DWOP_INPUTONLY | DWOP_COLORKEYING | DWOP_ALPHACHANNEL)) && (opaque=*update,dfb_region_intersect( &opaque, sawwin->dst.x, sawwin->dst.y, sawwin->dst.x + sawwin->dst.w - 1, sawwin->dst.y + sawwin->dst.h - 1 ) ) )||( //can skip opaque region? (options & DWOP_ALPHACHANNEL) && (options & DWOP_OPAQUE_REGION) && (window->config.opacity == 0xff) && !(options & DWOP_COLORKEYING) && (opaque=*update,dfb_region_intersect( &opaque, /* FIXME: Scaling */ sawwin->dst.x + window->config.opaque.x1, sawwin->dst.y + window->config.opaque.y1, sawwin->dst.x + window->config.opaque.x2, sawwin->dst.y + window->config.opaque.y2 )) ) )) { /* left */ if (opaque.x1 != update->x1) { DFBRegion left = { update->x1, opaque.y1, opaque.x1-1, opaque.y2}; wind_of_change( sawman, tier, &left, flags, current-1, changed ); } /* upper */ if (opaque.y1 != update->y1) { DFBRegion upper = { update->x1, update->y1, update->x2, opaque.y1-1}; wind_of_change( sawman, tier, &upper, flags, current-1, changed ); } /* right */ if (opaque.x2 != update->x2) { DFBRegion right = { opaque.x2+1, opaque.y1, update->x2, opaque.y2}; wind_of_change( sawman, tier, &right, flags, current-1, changed ); } /* lower */ if (opaque.y2 != update->y2) { DFBRegion lower = { update->x1, opaque.y2+1, update->x2, update->y2}; wind_of_change( sawman, tier, &lower, flags, current-1, changed ); } return; } } D_DEBUG_AT( SaWMan_Update, "+ UPDATE %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( update ) ); dfb_updates_add( &tier->updates, update ); } static void wind_of_showing( SaWMan *sawman, SaWManTier *tier, DFBRegion *update, int current, int changed, bool *ret_showing ) { D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); D_ASSERT( update != NULL ); if (*ret_showing) return; /* loop through windows above */ for (; current > changed; current--) { CoreWindow *window; SaWManWindow *sawwin; DFBRegion opaque; DFBWindowOptions options; D_ASSERT( changed >= 0 ); D_ASSERT( current >= changed ); D_ASSERT( current < fusion_vector_size( &sawman->layout ) ); sawwin = fusion_vector_at( &sawman->layout, current ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); options = window->config.options; /* can skip opaque region */ if ((tier->classes & (1 << window->config.stacking)) && ( ( //can skip all opaque window? (window->config.opacity == 0xff) && !(options & (DWOP_COLORKEYING | DWOP_ALPHACHANNEL)) && (opaque=*update,dfb_region_intersect( &opaque, sawwin->dst.x, sawwin->dst.y, sawwin->dst.x + sawwin->dst.w - 1, sawwin->dst.y + sawwin->dst.h - 1 ) ) )||( //can skip opaque region? (options & DWOP_ALPHACHANNEL) && (options & DWOP_OPAQUE_REGION) && (window->config.opacity == 0xff) && !(options & DWOP_COLORKEYING) && (opaque=*update,dfb_region_intersect( &opaque, /* FIXME: Scaling */ sawwin->dst.x + window->config.opaque.x1, sawwin->dst.y + window->config.opaque.y1, sawwin->dst.x + window->config.opaque.x2, sawwin->dst.y + window->config.opaque.y2 )) ) )) { /* left */ if (opaque.x1 != update->x1) { DFBRegion left = { update->x1, opaque.y1, opaque.x1-1, opaque.y2}; wind_of_showing( sawman, tier, &left, current-1, changed, ret_showing ); } /* upper */ if (opaque.y1 != update->y1) { DFBRegion upper = { update->x1, update->y1, update->x2, opaque.y1-1}; wind_of_showing( sawman, tier, &upper, current-1, changed, ret_showing ); } /* right */ if (opaque.x2 != update->x2) { DFBRegion right = { opaque.x2+1, opaque.y1, update->x2, opaque.y2}; wind_of_showing( sawman, tier, &right, current-1, changed, ret_showing ); } /* lower */ if (opaque.y2 != update->y2) { DFBRegion lower = { update->x1, opaque.y2+1, update->x2, update->y2}; wind_of_showing( sawman, tier, &lower, current-1, changed, ret_showing ); } return; } } *ret_showing = true; } static void update_region( SaWMan *sawman, SaWManTier *tier, CardState *state, int start, int x1, int y1, int x2, int y2 ) { int i = start; DFBRegion region = { x1, y1, x2, y2 }; CoreWindow *window = NULL; SaWManWindow *sawwin = NULL; D_DEBUG_AT( SaWMan_Update, "%s( %p, %d, %d,%d - %d,%d )\n", __FUNCTION__, tier, start, x1, y1, x2, y2 ); D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( start < fusion_vector_size( &sawman->layout ) ); D_ASSUME( x1 <= x2 ); D_ASSUME( y1 <= y2 ); if (x1 > x2 || y1 > y2) return; /* Find next intersecting window. */ while (i >= 0) { sawwin = fusion_vector_at( &sawman->layout, i ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); if (SAWMAN_VISIBLE_WINDOW( window ) && (tier->classes & (1 << window->config.stacking))) { if (dfb_region_intersect( ®ion, DFB_REGION_VALS_FROM_RECTANGLE( &sawwin->bounds ))) break; } i--; } /* Intersecting window found? */ if (i >= 0) { D_MAGIC_ASSERT( sawwin, SaWManWindow ); D_MAGIC_COREWINDOW_ASSERT( window ); if (D_FLAGS_ARE_SET( window->config.options, DWOP_ALPHACHANNEL | DWOP_OPAQUE_REGION )) { DFBRegion opaque = DFB_REGION_INIT_TRANSLATED( &window->config.opaque, sawwin->bounds.x, sawwin->bounds.y ); if (!dfb_region_region_intersect( &opaque, ®ion )) { update_region( sawman, tier, state, i-1, x1, y1, x2, y2 ); sawman_draw_window( tier, sawwin, state, ®ion, true ); } else { if ((window->config.opacity < 0xff) || (window->config.options & DWOP_COLORKEYING)) { /* draw everything below */ update_region( sawman, tier, state, i-1, x1, y1, x2, y2 ); } else { /* left */ if (opaque.x1 != x1) update_region( sawman, tier, state, i-1, x1, opaque.y1, opaque.x1-1, opaque.y2 ); /* upper */ if (opaque.y1 != y1) update_region( sawman, tier, state, i-1, x1, y1, x2, opaque.y1-1 ); /* right */ if (opaque.x2 != x2) update_region( sawman, tier, state, i-1, opaque.x2+1, opaque.y1, x2, opaque.y2 ); /* lower */ if (opaque.y2 != y2) update_region( sawman, tier, state, i-1, x1, opaque.y2+1, x2, y2 ); } /* left */ if (opaque.x1 != region.x1) { DFBRegion r = { region.x1, opaque.y1, opaque.x1 - 1, opaque.y2 }; sawman_draw_window( tier, sawwin, state, &r, true ); } /* upper */ if (opaque.y1 != region.y1) { DFBRegion r = { region.x1, region.y1, region.x2, opaque.y1 - 1 }; sawman_draw_window( tier, sawwin, state, &r, true ); } /* right */ if (opaque.x2 != region.x2) { DFBRegion r = { opaque.x2 + 1, opaque.y1, region.x2, opaque.y2 }; sawman_draw_window( tier, sawwin, state, &r, true ); } /* lower */ if (opaque.y2 != region.y2) { DFBRegion r = { region.x1, opaque.y2 + 1, region.x2, region.y2 }; sawman_draw_window( tier, sawwin, state, &r, true ); } /* inner */ sawman_draw_window( tier, sawwin, state, &opaque, false ); } } else { if (SAWMAN_TRANSLUCENT_WINDOW( window )) { /* draw everything below */ update_region( sawman, tier, state, i-1, x1, y1, x2, y2 ); } else { DFBRegion dst = DFB_REGION_INIT_FROM_RECTANGLE( &sawwin->dst ); dfb_region_region_intersect( &dst, ®ion ); /* left */ if (dst.x1 != x1) update_region( sawman, tier, state, i-1, x1, dst.y1, dst.x1-1, dst.y2 ); /* upper */ if (dst.y1 != y1) update_region( sawman, tier, state, i-1, x1, y1, x2, dst.y1-1 ); /* right */ if (dst.x2 != x2) update_region( sawman, tier, state, i-1, dst.x2+1, dst.y1, x2, dst.y2 ); /* lower */ if (dst.y2 != y2) update_region( sawman, tier, state, i-1, x1, dst.y2+1, x2, y2 ); } sawman_draw_window( tier, sawwin, state, ®ion, true ); } } else sawman_draw_background( tier, state, ®ion ); } static void repaint_tier( SaWMan *sawman, SaWManTier *tier, const DFBRegion *updates, int num_updates, DFBSurfaceFlipFlags flags ) { int i; CoreLayer *layer; CoreLayerRegion *region; CardState *state; CoreSurface *surface; DFBRegion cursor_inter; CoreWindowStack *stack; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); D_ASSERT( updates != NULL ); D_ASSERT( num_updates > 0 ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); stack = tier->stack; D_ASSERT( stack != NULL ); region = tier->region; D_ASSERT( region != NULL ); layer = dfb_layer_at( tier->layer_id ); state = &layer->state; surface = region->surface; if (/*!data->active ||*/ !surface) return; D_DEBUG_AT( SaWMan_Update, "%s( %p, %p )\n", __FUNCTION__, sawman, tier ); /* Set destination. */ state->destination = surface; state->modified |= SMF_DESTINATION; for (i=0; i %d, %d - %dx%d (%d)\n", DFB_RECTANGLE_VALS_FROM_REGION( update ), i ); dfb_state_set_dst_colorkey( state, dfb_color_to_pixel( region->config.format, region->config.src_key.r, region->config.src_key.g, region->config.src_key.b ) ); /* Set clipping region. */ dfb_state_set_clip( state, update ); /* Compose updated region. */ update_region( sawman, tier, state, fusion_vector_size( &sawman->layout ) - 1, update->x1, update->y1, update->x2, update->y2 ); /* Update cursor? */ cursor_inter = tier->cursor_region; if (tier->cursor_drawn && dfb_region_region_intersect( &cursor_inter, update )) { int x, y; DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &cursor_inter ); D_ASSUME( tier->cursor_bs_valid ); dfb_gfx_copy_to( surface, tier->cursor_bs, &rect, rect.x - tier->cursor_region.x1, rect.y - tier->cursor_region.y1, true ); x = (s64) stack->cursor.x * (s64) tier->size.w / (s64) sawman_config->resolution.w; y = (s64) stack->cursor.y * (s64) tier->size.h / (s64) sawman_config->resolution.h; sawman_draw_cursor( stack, state, &cursor_inter, x, y ); } } /* Reset destination. */ state->destination = NULL; state->modified |= SMF_DESTINATION; /* Software cursor code relies on a valid back buffer. */ if (stack->cursor.enabled) flags |= DSFLIP_BLIT; for (i=0; ilock )) return; buffer = dfb_surface_get_buffer( surface, CSBR_FRONT ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); ret = dfb_surface_buffer_dump( buffer, "/", "tier" ); fusion_skirmish_dismiss( &surface->lock ); } #endif if (1) { SaWManTierUpdate update; direct_memcpy( &update.regions[0], updates, sizeof(DFBRegion) * num_updates ); update.num_regions = num_updates; fusion_reactor_dispatch_channel( tier->reactor, SAWMAN_TIER_UPDATE, &update, sizeof(update), true, NULL ); } } static SaWManWindow * get_single_window( SaWMan *sawman, SaWManTier *tier, bool *ret_none ) { int n; SaWManWindow *sawwin; SaWManWindow *single = NULL; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); fusion_vector_foreach_reverse (sawwin, n, sawman->layout) { CoreWindow *window; D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); if (SAWMAN_VISIBLE_WINDOW(window) && (tier->classes & (1 << window->config.stacking))) { if ( single || ( window->caps & (DWCAPS_INPUTONLY | DWCAPS_COLOR) ) || ( window->config.options & DWOP_INPUTONLY ) ) return NULL; single = sawwin; if (single->dst.x == 0 && single->dst.y == 0 && single->dst.w == tier->size.w && single->dst.h == tier->size.h && !SAWMAN_TRANSLUCENT_WINDOW(window)) break; } } if (ret_none && !single) *ret_none = true; return single; } static bool get_border_only( SaWMan *sawman, SaWManTier *tier ) { int n; SaWManWindow *sawwin; bool none = true; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); fusion_vector_foreach_reverse (sawwin, n, sawman->layout) { CoreWindow *window; D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_MAGIC_COREWINDOW_ASSERT( window ); none = false; if ( SAWMAN_VISIBLE_WINDOW(window) && !(window->caps & DWCAPS_INPUTONLY) && !(window->config.options & DWOP_INPUTONLY) ) return false; } return !none; } static bool windows_updating( SaWMan *sawman, SaWManTier *tier ) { int i; SaWManWindow *window; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( tier, SaWManTier ); fusion_vector_foreach (window, i, sawman->layout) { D_MAGIC_ASSERT( window, SaWManWindow ); if (window->flags & SWMWF_UPDATING) { long long diff = direct_clock_get_millis() - window->update_ms; if (!sawman_config->flip_once_timeout || diff < sawman_config->flip_once_timeout) { D_DEBUG_AT( SaWMan_FlipOnce, " -> update blocking on window id %u (%lld ms, flags 0x%08x)\n", window->id, diff, window->flags ); return true; } D_DEBUG_AT( SaWMan_FlipOnce, " -> ignoring blocking of window id %u (%lld ms, flags 0x%08x)\n", window->id, diff, window->flags ); } } D_DEBUG_AT( SaWMan_FlipOnce, " -> update not blocked by any window\n" ); return false; } /* FIXME: Split up in smaller functions and clean up things like forcing reconfiguration. */ DirectResult sawman_process_updates( SaWMan *sawman, DFBSurfaceFlipFlags flags ) { DirectResult ret; int idx = -1; SaWManTier *tier; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); D_DEBUG_AT( SaWMan_Update, "%s( %p, 0x%08x )\n", __FUNCTION__, sawman, flags ); if (sawman->focused_window_switched) { SaWManWindow *to = sawman->focused_window_to; if (to) { CoreWindow *window; window = to->window; D_MAGIC_ASSERT( window, CoreWindow ); if (window->config.cursor_flags & DWCF_INVISIBLE) { /* Update cursor */ sawman_window_apply_cursor_flags( sawman, to ); } if (window->cursor.surface) { D_DEBUG_AT( SaWMan_Focus, " -> switching to window's cursor shape\n" ); dfb_windowstack_cursor_set_shape( window->stack, window->cursor.surface, window->cursor.hot_x, window->cursor.hot_y ); } if (!(window->config.cursor_flags & DWCF_INVISIBLE)) { /* Update cursor */ sawman_window_apply_cursor_flags( sawman, to ); } } else { SaWManTier *tier = (SaWManTier*) sawman->tiers; D_MAGIC_ASSERT( tier, SaWManTier ); if (tier->stack->cursor.opacity) { D_DEBUG_AT( SaWMan_Focus, " -> hiding cursor...\n" ); tier->stack->cursor.opacity = 0; dfb_wm_update_cursor( tier->stack, CCUF_OPACITY ); } else D_DEBUG_AT( SaWMan_Focus, " -> cursor already hidden\n" ); } sawman->focused_window_switched = false; } direct_list_foreach (tier, sawman->tiers) { int n, d; int total; int bounding; bool none = false; bool border_only; SaWManWindow *single; CoreLayer *layer; CoreLayerShared *shared; int screen_width; int screen_height; DFBColorKey single_key; idx++; layer = dfb_layer_at( tier->layer_id ); D_ASSERT( layer != NULL ); shared = layer->shared; D_ASSERT( shared != NULL ); D_MAGIC_ASSERT( tier, SaWManTier ); if (!tier->updates.num_regions) continue; if (tier->update_once) { if (windows_updating( sawman, tier )) continue; tier->update_once = false; } D_DEBUG_AT( SaWMan_Update, " -> %d updates (tier %d, layer %d)\n", tier->updates.num_regions, idx, tier->layer_id ); D_ASSERT( tier->region != NULL ); D_DEBUG_AT( SaWMan_Update, " -> [%d] %d updates, bounding %dx%d\n", tier->layer_id, tier->updates.num_regions, tier->updates.bounding.x2 - tier->updates.bounding.x1 + 1, tier->updates.bounding.y2 - tier->updates.bounding.y1 + 1 ); if (!tier->config.width || !tier->config.height) continue; dfb_screen_get_screen_size( layer->screen, &screen_width, &screen_height ); single = get_single_window( sawman, tier, &none ); if (none && !sawman_config->show_empty) { if (tier->active) { D_DEBUG_AT( SaWMan_Auto, " -> Disabling region...\n" ); tier->active = false; tier->single_window = NULL; /* enforce configuration to reallocate buffers */ dfb_layer_region_disable( tier->region ); if (sawman->cursor.context && tier->context->layer_id == sawman->cursor.context->layer_id) { dfb_layer_activate_context( dfb_layer_at(sawman->cursor.context->layer_id), sawman->cursor.context ); dfb_layer_region_flip_update( sawman->cursor.region, NULL, DSFLIP_NONE ); } } dfb_updates_reset( &tier->updates ); continue; } border_only = get_border_only( sawman, tier ); /* Remember color key before single mode is activated. */ if (!tier->single_mode) tier->key = tier->context->primary.config.src_key; /* If the first mode after turning off the layer is not single, then we need this to force a reconfiguration to reallocate the buffers. */ if (!tier->active) { tier->single_mode = true; /* avoid endless loop */ tier->border_only = !border_only; /* enforce configuration to reallocate buffers */ } if (single && !border_only) { CoreWindow *window; CoreSurface *surface; DFBDisplayLayerOptions options = DLOP_NONE; DFBRectangle dst = single->dst; DFBRectangle src = single->src; DFBRegion clip = DFB_REGION_INIT_FROM_DIMENSION( &tier->size ); if (shared->description.caps & DLCAPS_SCREEN_LOCATION) { dst.x = dst.x * screen_width / tier->size.w; dst.y = dst.y * screen_height / tier->size.h; dst.w = dst.w * screen_width / tier->size.w; dst.h = dst.h * screen_height / tier->size.h; } else { if (dst.w != src.w || dst.h != src.h) goto no_single; if (shared->description.caps & DLCAPS_SCREEN_POSITION) { dfb_rectangle_intersect_by_region( &dst, &clip ); src.x += dst.x - single->dst.x; src.y += dst.y - single->dst.y; src.w = dst.w; src.h = dst.h; dst.x += (screen_width - tier->size.w) / 2; dst.y += (screen_height - tier->size.h) / 2; } } #ifdef SAWMAN_NO_LAYER_DOWNSCALE if (rect.w < src.w) goto no_single; #endif #ifdef SAWMAN_NO_LAYER_DST_WINDOW if (dst.x != 0 || dst.y != 0 || dst.w != screen_width || dst.h != screen_height) goto no_single; #endif window = single->window; D_MAGIC_COREWINDOW_ASSERT( window ); surface = window->surface; D_ASSERT( surface != NULL ); if (window->config.options & DWOP_ALPHACHANNEL) options |= DLOP_ALPHACHANNEL; if (window->config.options & DWOP_COLORKEYING) options |= DLOP_SRC_COLORKEY; single_key = tier->single_key; if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) { CorePalette *palette = surface->palette; D_ASSERT( palette != NULL ); D_ASSERT( palette->num_entries > 0 ); dfb_surface_set_palette( tier->region->surface, surface->palette ); if (options & DLOP_SRC_COLORKEY) { int index = window->config.color_key % palette->num_entries; single_key.r = palette->entries[index].r; single_key.g = palette->entries[index].g; single_key.b = palette->entries[index].b; single_key.index = index; } } else { DFBColor color; dfb_pixel_to_color( surface->config.format, window->config.color_key, &color ); single_key.r = color.r; single_key.g = color.g; single_key.b = color.b; single_key.index = window->config.color_key; } /* Complete reconfig? */ if (tier->single_window != single || !DFB_RECTANGLE_EQUAL( tier->single_src, src ) || tier->single_format != surface->config.format || tier->single_options != options) { DFBDisplayLayerConfig config; D_DEBUG_AT( SaWMan_Auto, " -> Switching to %dx%d [%dx%d] %s single mode for %p on %p...\n", single->src.w, single->src.h, src.w, src.h, dfb_pixelformat_name( surface->config.format ), single, tier ); config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_OPTIONS | DLCONF_BUFFERMODE; config.width = src.w; config.height = src.h; config.pixelformat = surface->config.format; config.options = options; config.buffermode = DLBM_FRONTONLY; sawman->callback.layer_reconfig.layer_id = tier->layer_id; sawman->callback.layer_reconfig.single = (SaWManWindowHandle) single; sawman->callback.layer_reconfig.config = config; switch (sawman_call( sawman, SWMCID_LAYER_RECONFIG, &sawman->callback.layer_reconfig )) { case DFB_OK: config = sawman->callback.layer_reconfig.config; case DFB_NOIMPL: /* continue, no change demanded */ break; default: goto no_single; } if (dfb_layer_context_test_configuration( tier->context, &config, NULL ) != DFB_OK) goto no_single; tier->single_mode = true; tier->single_window = single; tier->single_width = src.w; tier->single_height = src.h; tier->single_src = src; tier->single_dst = dst; tier->single_format = surface->config.format; tier->single_options = options; tier->single_key = single_key; tier->active = false; tier->region->state |= CLRSF_FROZEN; dfb_updates_reset( &tier->updates ); dfb_layer_context_set_configuration( tier->context, &config ); if (shared->description.caps & DLCAPS_SCREEN_LOCATION) dfb_layer_context_set_screenrectangle( tier->context, &dst ); else if (shared->description.caps & DLCAPS_SCREEN_POSITION) dfb_layer_context_set_screenposition( tier->context, dst.x, dst.y ); dfb_layer_context_set_src_colorkey( tier->context, tier->single_key.r, tier->single_key.g, tier->single_key.b, tier->single_key.index ); dfb_gfx_copy_to( surface, tier->region->surface, &src, 0, 0, false ); tier->active = true; if (sawman->cursor.context && tier->context->layer_id == sawman->cursor.context->layer_id) dfb_layer_activate_context( dfb_layer_at(tier->context->layer_id), tier->context ); dfb_layer_region_flip_update( tier->region, NULL, flags ); dfb_updates_reset( &tier->updates ); if (1) { SaWManTierUpdate update; update.regions[0].x1 = 0; update.regions[0].y1 = 0; update.regions[0].x2 = tier->single_width - 1; update.regions[0].y2 = tier->single_height - 1; update.num_regions = 1; fusion_reactor_dispatch_channel( tier->reactor, SAWMAN_TIER_UPDATE, &update, sizeof(update), true, NULL ); } continue; } /* Update destination window */ if (!DFB_RECTANGLE_EQUAL( tier->single_dst, dst )) { tier->single_dst = dst; D_DEBUG_AT( SaWMan_Auto, " -> Changing single destination to %d,%d-%dx%d.\n", DFB_RECTANGLE_VALS(&dst) ); dfb_layer_context_set_screenrectangle( tier->context, &dst ); } else dfb_gfx_copy_to( surface, tier->region->surface, &src, 0, 0, false ); /* Update color key */ if (!DFB_COLORKEY_EQUAL( single_key, tier->single_key )) { D_DEBUG_AT( SaWMan_Auto, " -> Changing single color key.\n" ); tier->single_key = single_key; dfb_layer_context_set_src_colorkey( tier->context, tier->single_key.r, tier->single_key.g, tier->single_key.b, tier->single_key.index ); } tier->active = true; dfb_layer_region_flip_update( tier->region, NULL, flags ); dfb_updates_reset( &tier->updates ); fusion_skirmish_notify( &sawman->lock ); continue; } no_single: if (tier->single_mode) { D_DEBUG_AT( SaWMan_Auto, " -> Switching back from single mode...\n" ); tier->border_only = !border_only; /* enforce switch */ } /* Switch border/default config? */ if (tier->border_only != border_only) { DFBDisplayLayerConfig *config; tier->border_only = border_only; if (border_only) config = &tier->border_config; else config = &tier->config; D_DEBUG_AT( SaWMan_Auto, " -> Switching to %dx%d %s %s mode.\n", config->width, config->height, dfb_pixelformat_name( config->pixelformat ), border_only ? "border" : "standard" ); sawman->callback.layer_reconfig.layer_id = tier->layer_id; sawman->callback.layer_reconfig.single = SAWMAN_WINDOW_NONE; sawman->callback.layer_reconfig.config = *config; ret = sawman_call( sawman, SWMCID_LAYER_RECONFIG, &sawman->callback.layer_reconfig ); /* on DFB_OK we try to overrule the default configuration */ if ( !ret && !dfb_layer_context_test_configuration( tier->context, &(sawman->callback.layer_reconfig.config), NULL ) ) { *config = sawman->callback.layer_reconfig.config; D_DEBUG_AT( SaWMan_Auto, " -> Overruled to %dx%d %s %s mode.\n", config->width, config->height, dfb_pixelformat_name( config->pixelformat ), border_only ? "border" : "standard" ); } tier->active = false; tier->region->state |= CLRSF_FROZEN; dfb_updates_reset( &tier->updates ); /* Temporarily to avoid configuration errors. */ dfb_layer_context_set_screenposition( tier->context, 0, 0 ); ret = dfb_layer_context_set_configuration( tier->context, config ); if (ret) { D_DERROR( ret, "SaWMan/Auto: Switching to standard mode failed!\n" ); /* fixme */ } tier->size.w = config->width; tier->size.h = config->height; /* Notify application manager about new tier size if previous mode was single. */ if (tier->single_mode) sawman_call( sawman, SWMCID_STACK_RESIZED, &tier->size ); if (shared->description.caps & DLCAPS_SCREEN_LOCATION) { DFBRectangle full = { 0, 0, screen_width, screen_height }; dfb_layer_context_set_screenrectangle( tier->context, &full ); } else if (shared->description.caps & DLCAPS_SCREEN_POSITION) { dfb_layer_context_set_screenposition( tier->context, (screen_width - config->width) / 2, (screen_height - config->height) / 2 ); } if (config->options & DLOP_SRC_COLORKEY) { if (DFB_PIXELFORMAT_IS_INDEXED( config->pixelformat )) { int index; CoreSurface *surface; CorePalette *palette; surface = tier->region->surface; D_MAGIC_ASSERT( surface, CoreSurface ); palette = surface->palette; D_ASSERT( palette != NULL ); D_ASSERT( palette->num_entries > 0 ); index = tier->key.index % palette->num_entries; dfb_layer_context_set_src_colorkey( tier->context, palette->entries[index].r, palette->entries[index].g, palette->entries[index].b, index ); } else dfb_layer_context_set_src_colorkey( tier->context, tier->key.r, tier->key.g, tier->key.b, tier->key.index ); } } if (!tier->active) { D_DEBUG_AT( SaWMan_Auto, " -> Activating tier...\n" ); tier->active = true; DFBRegion region = { 0, 0, tier->size.w - 1, tier->size.h - 1 }; dfb_updates_add( &tier->updates, ®ion ); if (sawman->cursor.context && tier->context->layer_id == sawman->cursor.context->layer_id) dfb_layer_activate_context( dfb_layer_at(tier->context->layer_id), tier->context ); } tier->single_mode = false; tier->single_window = NULL; if (!tier->updates.num_regions) continue; dfb_updates_stat( &tier->updates, &total, &bounding ); n = tier->updates.max_regions - tier->updates.num_regions + 1; d = n + 1; /* Try to optimize updates. In buffer swapping modes we can save the copy by updating everything. */ if ((total > tier->size.w * tier->size.h) || (total > tier->size.w * tier->size.h * 3 / 5 && (tier->context->config.buffermode == DLBM_BACKVIDEO || tier->context->config.buffermode == DLBM_TRIPLE))) { DFBRegion region = { 0, 0, tier->size.w - 1, tier->size.h - 1 }; repaint_tier( sawman, tier, ®ion, 1, flags ); } else if (tier->updates.num_regions < 2 || total < bounding * n / d) repaint_tier( sawman, tier, tier->updates.regions, tier->updates.num_regions, flags ); else repaint_tier( sawman, tier, &tier->updates.bounding, 1, flags ); dfb_updates_reset( &tier->updates ); fusion_skirmish_notify( &sawman->lock ); } return DFB_OK; } #endif // !DIRECTFB_PURE_VOODOO