/* (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. */ #include #include #include #include #include #include #include #include #include #include "isawmanmanager.h" D_DEBUG_DOMAIN( SaWMan_Manager, "SaWMan/Manager", "SaWMan Manager Interface" ); static void ISaWManManager_Destruct( ISaWManManager *thiz ) { ISaWManManager_data *data = thiz->priv; (void) data; DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult ISaWManManager_AddRef( ISaWManManager *thiz ) { DIRECT_INTERFACE_GET_DATA( ISaWManManager ) data->ref++; return DFB_OK; } static DirectResult ISaWManManager_Release( ISaWManManager *thiz ) { DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (--data->ref == 0) ISaWManManager_Destruct( thiz ); return DFB_OK; } static DirectResult ISaWManManager_QueueUpdate( ISaWManManager *thiz, DFBWindowStackingClass stacking, const DFBRegion *region ) { SaWMan *sawman; SaWManTier *tier; DFBRegion update; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!DFB_REGION_CHECK_IF( region )) return DFB_INVAREA; switch (stacking) { case DWSC_LOWER: case DWSC_MIDDLE: case DWSC_UPPER: break; default: return DFB_INVARG; } sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); tier = sawman_tier_by_class( sawman, stacking ); update = DFB_REGION_INIT_FROM_DIMENSION( &tier->size ); if (region && !dfb_region_region_intersect( &update, region )) return DFB_OK; dfb_updates_add( &tier->updates, &update ); return DFB_OK; } static DirectResult ISaWManManager_ProcessUpdates( ISaWManManager *thiz, DFBSurfaceFlipFlags flags ) { SaWMan *sawman; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); return sawman_process_updates( sawman, flags ); } static DirectResult ISaWManManager_CloseWindow( ISaWManManager *thiz, SaWManWindowHandle handle ) { SaWMan *sawman; DFBWindowEvent event; SaWManWindow *window = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!window) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); event.type = DWET_CLOSE; dfb_window_post_event( window->window, &event ); return DFB_OK; } static DirectResult ISaWManManager_SetVisible( ISaWManManager *thiz, SaWManWindowHandle handle, DFBBoolean visible ) { SaWMan *sawman; SaWManWindow *window = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!window) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); D_UNIMPLEMENTED(); return DFB_UNIMPLEMENTED;// sawman_set_visible( sawman, window ); } static DirectResult ISaWManManager_SwitchFocus( ISaWManManager *thiz, SaWManWindowHandle handle ) { SaWMan *sawman; SaWManWindow *window = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!window) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); return sawman_switch_focus( sawman, window ); } static DirectResult ISaWManManager_GetSize( ISaWManManager *thiz, DFBWindowStackingClass stacking, DFBDimension *ret_size ) { SaWMan *sawman; SaWManTier *tier; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) switch (stacking) { case DWSC_LOWER: case DWSC_MIDDLE: case DWSC_UPPER: break; default: return DFB_INVARG; } if (!ret_size) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); tier = sawman_tier_by_class( sawman, stacking ); *ret_size = tier->size; return DFB_OK; } static DirectResult ISaWManManager_InsertWindow( ISaWManManager *thiz, SaWManWindowHandle handle, SaWManWindowHandle relative, SaWManWindowRelation relation ) { SaWMan *sawman; SaWManWindow *window = (SaWManWindow*)handle; SaWManWindow *sawrel = (SaWManWindow*)relative; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!window) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); D_MAGIC_ASSERT_IF( sawrel, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); return sawman_insert_window( sawman, window, sawrel, (relation == SWMWR_TOP) ? DFB_TRUE : DFB_FALSE ); } static DirectResult ISaWManManager_RemoveWindow( ISaWManManager *thiz, SaWManWindowHandle handle ) { SaWMan *sawman; SaWManWindow *window = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!window) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); return sawman_remove_window( sawman, window ); } static DirectResult ISaWManManager_SetScalingMode( ISaWManManager *thiz, SaWManScalingMode mode ) { SaWMan *sawman; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (mode != SWMSM_STANDARD && mode != SWMSM_SMOOTH_SW) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); if (sawman->scaling_mode != mode) { SaWManTier *tier; sawman->scaling_mode = mode; direct_list_foreach (tier, sawman->tiers) { DFBRegion update = DFB_REGION_INIT_FROM_DIMENSION( &tier->size ); dfb_updates_add( &tier->updates, &update ); } } return DFB_OK; } static void reset_geometry_to_nonfollow( SaWManWindow *window ) { if (window->window->config.dst_geometry.mode == DWGM_FOLLOW) window->window->config.dst_geometry.mode = DWGM_DEFAULT; if (window->window->config.src_geometry.mode == DWGM_FOLLOW) window->window->config.src_geometry.mode = DWGM_DEFAULT; } static DirectResult ISaWManManager_SetWindowConfig ( ISaWManManager *thiz, SaWManWindowHandle handle, SaWManWindowConfigFlags flags, SaWManWindowConfig *config ) { DFBResult ret; SaWMan *sawman; SaWManWindow *sawwin = (SaWManWindow*)handle; CoreWindow *window; /* not yet implemented: SWMCF_KEY_SELECTION */ if (flags & ~(SWMCF_ALL - SWMCF_KEY_SELECTION)) return DFB_INVARG; if( config == NULL ) return DFB_INVARG; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_ASSERT( window != NULL ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); if (flags & CWCF_OPTIONS) { if ((window->config.options & DWOP_SCALE) && !(config->options & DWOP_SCALE) && window->surface) { /* scaling turned off - see if we need to reallocate the surface */ if (window->config.bounds.w != window->surface->config.size.w || window->config.bounds.h != window->surface->config.size.h) { ret = dfb_surface_reformat( window->surface, window->config.bounds.w, window->config.bounds.h, window->surface->config.format ); if (ret) { D_DERROR( ret, "WM/SaWMan: Could not resize surface " "(%dx%d -> %dx%d) to remove DWOP_SCALE!\n", window->surface->config.size.w, window->surface->config.size.h, window->config.bounds.w, window->config.bounds.h ); return ret; } } } if (config->options & (DWOP_KEEP_ABOVE | DWOP_KEEP_UNDER)) { D_ASSERT( sawwin->parent ); if (config->options & DWOP_KEEP_ABOVE) { D_ASSERT( sawman_window_priority(sawwin->parent) <= sawman_window_priority(sawwin) ); sawman_insert_window( sawman, sawwin, sawwin->parent, true ); } else { D_ASSERT( sawman_window_priority(sawwin->parent) >= sawman_window_priority(sawwin) ); sawman_insert_window( sawman, sawwin, sawwin->parent, false ); } sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_UPDATE_BORDER | SWMUF_FORCE_COMPLETE ); } window->config.options = config->options; } if (flags & CWCF_EVENTS) window->config.events = config->events; if (flags & CWCF_COLOR) window->config.color = config->color; if (flags & CWCF_COLOR_KEY) window->config.color_key = config->color_key; if (flags & CWCF_OPAQUE) window->config.opaque = config->opaque; if (flags & CWCF_STACKING) sawman_restack_window( sawman, sawwin, sawwin, 0, config->stacking ); if (flags & CWCF_OPACITY) sawman_set_opacity( sawman, sawwin, config->opacity ); if( flags & (SWMCF_POSITION | SWMCF_SIZE) ) { if( flags == SWMCF_POSITION ) { window->config.bounds.x = config->bounds.x; window->config.bounds.y = config->bounds.y; } else if( flags == SWMCF_SIZE ) { window->config.bounds.w = config->bounds.w; window->config.bounds.h = config->bounds.h; } else window->config.bounds = config->bounds; } if (flags & CWCF_SRC_GEOMETRY) window->config.src_geometry = config->src_geometry; if (flags & CWCF_DST_GEOMETRY) window->config.dst_geometry = config->dst_geometry; if (flags & SWMCF_ASSOCIATION && window->config.association != config->association) { SaWManWindow *parent = sawwin->parent; /* Dissociate first */ if (sawwin->parent_window) { int index; dfb_window_unlink( &sawwin->parent_window ); index = fusion_vector_index_of( &parent->children, sawwin ); D_ASSERT( index >= 0 ); D_ASSERT( index < parent->children.count ); fusion_vector_remove( &parent->children, index ); sawwin->parent = NULL; window->config.association = 0; } /* Lookup new parent window. */ if (config->association) { D_DEBUG_AT( SaWMan_Manager, " -> new parent win id %u\n", config->association ); direct_list_foreach (parent, sawman->windows) { D_MAGIC_ASSERT( parent, SaWManWindow ); D_ASSERT( parent->window != NULL ); if (parent->id == config->association) break; } if (!parent) { D_ERROR( "SaWMan/WM: Can't find parent window with ID %d!\n", config->association ); reset_geometry_to_nonfollow( sawwin ); return DFB_IDNOTFOUND; } D_MAGIC_ASSERT( parent, SaWManWindow ); D_ASSERT( parent->window != NULL ); if (parent->window->toplevel != window->toplevel) { D_ERROR( "SaWMan/WM: Can't associate windows with different toplevel!\n" ); reset_geometry_to_nonfollow( sawwin ); return DFB_INVARG; } D_DEBUG_AT( SaWMan_Manager, " -> parent window %p\n", parent ); ret = dfb_window_link( &sawwin->parent_window, parent->window ); if (ret) { D_DERROR( ret, "SaWMan/WM: Can't link parent window with ID %d!\n", config->association ); reset_geometry_to_nonfollow( sawwin ); return ret; } ret = fusion_vector_add( &parent->children, sawwin ); if (ret) { dfb_window_unlink( &sawwin->parent_window ); reset_geometry_to_nonfollow( sawwin ); return ret; } sawwin->parent = parent; /* Write back new association */ window->config.association = config->association; } else reset_geometry_to_nonfollow( sawwin ); } if (flags & (CWCF_POSITION | CWCF_SIZE | CWCF_SRC_GEOMETRY | CWCF_DST_GEOMETRY | SWMCF_ASSOCIATION)) sawman_update_geometry( sawwin ); /* Send notification to windows watchers */ CoreLayer *layer = dfb_layer_at( sawwin->stack->context->layer_id ); dfb_wm_dispatch_WindowConfig( layer->core, window, flags ); return DFB_OK; } static DirectResult ISaWManManager_SendWindowEvent( ISaWManManager *thiz, SaWManWindowHandle handle, const DFBWindowEvent *event ) { SaWMan *sawman; SaWManWindow *window = (SaWManWindow*)handle; DFBWindowEvent evt; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!event || (handle == SAWMAN_WINDOW_NONE)) return DFB_INVARG; /* Only key events! */ if (event->type != DWET_KEYDOWN && event->type != DWET_KEYUP) return DFB_UNSUPPORTED; /* Don't return same event twice! */ if (event->flags & DWEF_RETURNED) return DFB_LIMITEXCEEDED; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( window, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); evt = *event; sawman_post_event( sawman, window, &evt ); return DFB_OK; } static DirectResult ISaWManManager_Lock( ISaWManManager *thiz ) { SaWMan *sawman; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); return sawman_lock( sawman ); } static DirectResult ISaWManManager_Unlock( ISaWManManager *thiz ) { SaWMan *sawman; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); return sawman_unlock( sawman ); } static DirectResult ISaWManManager_GetWindowInfo( ISaWManManager *thiz, SaWManWindowHandle handle, SaWManWindowInfo *info ) { SaWMan *sawman; SaWManWindow *sawwin = (SaWManWindow*)handle; CoreWindow *window; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!info || (handle == SAWMAN_WINDOW_NONE)) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); window = sawwin->window; D_ASSERT( window != NULL ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); info->handle = handle; info->caps = sawwin->caps; SAWMANWINDOWCONFIG_COPY( &info->config, &window->config ) info->config.key_selection = window->config.key_selection; info->config.keys = window->config.keys; info->config.num_keys = window->config.num_keys; info->resource_id = window->resource_id; info->win_id = window->id; info->flags = sawwin->flags | (window->flags & CWF_FOCUSED ? SWMWF_FOCUSED : 0) | (window->flags & CWF_ENTERED ? SWMWF_ENTERED : 0); return DFB_OK; } static DirectResult ISaWManManager_GetProcessInfo( ISaWManManager *thiz, SaWManWindowHandle handle, SaWManProcess *process ) { SaWMan *sawman; SaWManWindow *sawwin = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!process || (handle == SAWMAN_WINDOW_NONE)) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); *process = *sawwin->process; return DFB_OK; } static DirectResult ISaWManManager_IsWindowShowing( ISaWManManager *thiz, SaWManWindowHandle handle, DFBBoolean *ret_showing ) { DFBResult ret; bool showing; SaWMan *sawman; SaWManWindow *sawwin = (SaWManWindow*)handle; DIRECT_INTERFACE_GET_DATA( ISaWManManager ) if (!ret_showing) return DFB_INVARG; sawman = data->sawman; D_MAGIC_ASSERT( sawman, SaWMan ); D_MAGIC_ASSERT( sawwin, SaWManWindow ); FUSION_SKIRMISH_ASSERT( &sawman->lock ); ret = sawman_showing_window( sawman, sawwin, &showing ); if (ret) return ret; *ret_showing = showing ? DFB_TRUE : DFB_FALSE; return DFB_OK; } DirectResult ISaWManManager_Construct( ISaWManManager *thiz, SaWMan *sawman, SaWManProcess *process ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, ISaWManManager ) data->ref = 1; data->sawman = sawman; data->process = process; thiz->AddRef = ISaWManManager_AddRef; thiz->Release = ISaWManManager_Release; thiz->QueueUpdate = ISaWManManager_QueueUpdate; thiz->ProcessUpdates = ISaWManManager_ProcessUpdates; thiz->CloseWindow = ISaWManManager_CloseWindow; thiz->SetVisible = ISaWManManager_SetVisible; thiz->SwitchFocus = ISaWManManager_SwitchFocus; thiz->GetSize = ISaWManManager_GetSize; thiz->InsertWindow = ISaWManManager_InsertWindow; thiz->RemoveWindow = ISaWManManager_RemoveWindow; thiz->SetScalingMode = ISaWManManager_SetScalingMode; thiz->SetWindowConfig = ISaWManManager_SetWindowConfig; thiz->SendWindowEvent = ISaWManManager_SendWindowEvent; thiz->Lock = ISaWManManager_Lock; thiz->Unlock = ISaWManManager_Unlock; thiz->GetWindowInfo = ISaWManManager_GetWindowInfo; thiz->GetProcessInfo = ISaWManManager_GetProcessInfo; thiz->IsWindowShowing = ISaWManManager_IsWindowShowing; return DFB_OK; }