From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/SaWMan/wm/sawman/sawman_wm.c | 3590 +++++++++++++++++++++++++++++++++++ 1 file changed, 3590 insertions(+) create mode 100755 Source/SaWMan/wm/sawman/sawman_wm.c (limited to 'Source/SaWMan/wm/sawman/sawman_wm.c') diff --git a/Source/SaWMan/wm/sawman/sawman_wm.c b/Source/SaWMan/wm/sawman/sawman_wm.c new file mode 100755 index 0000000..a401f27 --- /dev/null +++ b/Source/SaWMan/wm/sawman/sawman_wm.c @@ -0,0 +1,3590 @@ +/* + (c) Copyright 2001-2007 directfb.org + (c) Copyright 2000-2004 convergence (integrated) media GmbH. + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann and + Ville Syrjälä . + + 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "sawman_draw.h" + + +DFB_WINDOW_MANAGER( sawman ) + + +D_DEBUG_DOMAIN( SaWMan_WM , "SaWMan/WM", "SaWMan window manager module" ); +D_DEBUG_DOMAIN( SaWMan_Cursor, "SaWMan/Cursor", "SaWMan window manager cursor" ); +D_DEBUG_DOMAIN( SaWMan_Stacking, "SaWMan/Stacking", "SaWMan window manager stacking" ); +D_DEBUG_DOMAIN( SaWMan_FlipOnce, "SaWMan/FlipOnce", "SaWMan window manager flip once" ); + +/**********************************************************************************************************************/ + +typedef struct { + CoreDFB *core; + FusionWorld *world; + SaWMan *sawman; + SaWManProcess *process; +} WMData; + +/**********************************************************************************************************************/ + +static int +keys_compare( const void *key1, + const void *key2 ) +{ + return *(DFBInputDeviceKeySymbol*) key1 - *(DFBInputDeviceKeySymbol*) key2; +} + +static void +send_key_event( SaWMan *sawman, + SaWManWindow *sawwin, + const DFBInputEvent *event ) +{ + DFBWindowEvent we; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_ASSERT( event != NULL ); + + we.type = (event->type == DIET_KEYPRESS) ? DWET_KEYDOWN : DWET_KEYUP; + we.flags = 0; + we.key_code = event->key_code; + we.key_id = event->key_id; + we.key_symbol = event->key_symbol; + + if (event->flags & DIEF_REPEAT) + we.flags |= DWEF_REPEAT; + + sawman_post_event( sawman, sawwin, &we ); +} + +static void +send_button_event( SaWMan *sawman, + SaWManWindow *sawwin, + CoreWindowStack *stack, + const DFBInputEvent *event ) +{ + DFBWindowEvent we; + CoreWindow *window; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_ASSERT( stack != NULL ); + D_ASSERT( event != NULL ); + + window = sawwin->window; + + D_ASSERT( window != NULL ); + + we.type = (event->type == DIET_BUTTONPRESS) ? DWET_BUTTONDOWN : DWET_BUTTONUP; + we.button = event->button; + + sawman_window_get_cursor_position( sawman, stack, sawwin, &we.x, &we.y, &we.cx, &we.cy ); + + if (window->config.options & DWOP_SCALE) { + D_ASSERT( window->surface != NULL ); + + we.x = we.x * window->surface->config.size.w / sawwin->bounds.w; + we.y = we.y * window->surface->config.size.h / sawwin->bounds.h; + } + + if (event->flags & DIEF_REPEAT) + we.flags |= DWEF_REPEAT; + + sawman_post_event( sawman, sawwin, &we ); +} + +/**********************************************************************************************************************/ + +static SaWManWindow * +get_keyboard_window( StackData *data, + const DFBInputEvent *event ) +{ + SaWMan *sawman; + SaWManWindow *sawwin; + CoreWindow *window; + SaWManGrabbedKey *key; + + D_ASSERT( data != NULL ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_KEYPRESS || event->type == DIET_KEYRELEASE ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Check explicit key grabs first. */ + direct_list_foreach (key, sawman->grabbed_keys) { + if (key->symbol == event->key_symbol && + key->modifiers == sawman->modifiers) + return key->owner; + } + + /* Key is not grabbed, check for explicit keyboard grab or focus. */ + sawwin = sawman->keyboard_window ? + sawman->keyboard_window : sawman->focused_window; + if (!sawwin) + return NULL; + + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + window = sawwin->window; + D_ASSERT( window != NULL ); + + /* Check key selection. */ + switch (window->config.key_selection) { + case DWKS_ALL: + break; + + case DWKS_LIST: + D_ASSERT( window->config.keys != NULL ); + D_ASSERT( window->config.num_keys > 0 ); + + if (bsearch( &event->key_symbol, + window->config.keys, window->config.num_keys, + sizeof(DFBInputDeviceKeySymbol), keys_compare )) + break; + + /* fall through */ + + case DWKS_NONE: + return sawman->unselkeys_window; + } + + /* key is for this window */ + + /* only do implicit grabbing if we have a hardware key code */ + if( event->key_code == -1 ) + return sawwin; + + /* do implicit grabbing */ + if( event->type == DIET_KEYPRESS ) { + int i; + int free_key = -1; + + for (i=0; ikeys[i].code == event->key_code) + return sawman->keys[i].owner; + + /* Remember first free array item. */ + if (free_key == -1 && sawman->keys[i].code == -1) + free_key = i; + } + + /* Check if a free array item was found. */ + if (free_key == -1) { + D_WARN( "maximum number of owned keys reached" ); + return NULL; + } + + /* Implicitly grab the key. */ + sawman->keys[free_key].symbol = event->key_symbol; + sawman->keys[free_key].id = event->key_id; + sawman->keys[free_key].code = event->key_code; + sawman->keys[free_key].owner = sawwin; + + return sawwin; + } + else { + int i; + + /* Lookup owner and ungrab the key. */ + for (i=0; ikeys[i].code == event->key_code) { + sawman->keys[i].code = -1; + + /* Return owner (NULL if destroyed). */ + return sawman->keys[i].owner; + } + } + } + + /* No owner for release event found, discard it. */ + return NULL; +} + +/**********************************************************************************************************************/ + +static DFBResult +move_window( SaWMan *sawman, + SaWManWindow *sawwin, + int dx, + int dy ) +{ + DFBWindowEvent evt; + DFBRectangle *bounds; + CoreWindow *window; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + window = sawwin->window; + D_ASSERT( window != NULL ); + + bounds = &window->config.bounds; + bounds->x += dx; + bounds->y += dy; + + if (SAWMAN_VISIBLE_WINDOW(window) && (sawwin->flags & SWMWF_INSERTED)) { + DFBRegion region = { 0, 0, bounds->w - 1, bounds->h - 1 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + + dfb_region_translate( ®ion, -dx, -dy ); + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + + /* Send new position */ + evt.type = DWET_POSITION; + evt.x = bounds->x; + evt.y = bounds->y; + + sawman_post_event( sawman, sawwin, &evt ); + + return DFB_OK; +} + +static DFBResult +resize_window( SaWMan *sawman, + SaWManWindow *sawwin, + WMData *wm_data, + int width, + int height ) +{ + DFBResult ret; + DFBWindowEvent evt; + DFBRectangle *bounds; + CoreWindow *window; + int ow; + int oh; + + D_DEBUG_AT( SaWMan_WM, "resize_window( %d, %d )\n", width, height ); + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( width > 0 ); + D_ASSERT( height > 0 ); + + if (width > 4096 || height > 4096) + return DFB_LIMITEXCEEDED; + + window = sawwin->window; + D_ASSERT( window != NULL ); + + /* Resize the surface? */ + if (window->surface && !(window->config.options & DWOP_SCALE)) { + ret = dfb_surface_reformat( window->surface, + width, height, window->surface->config.format ); + if (ret) + return ret; + } + + bounds = &window->config.bounds; + ow = bounds->w; + oh = bounds->h; + + bounds->w = width; + bounds->h = height; + + dfb_region_intersect( &window->config.opaque, 0, 0, width - 1, height - 1 ); + + if (SAWMAN_VISIBLE_WINDOW (window) && (sawwin->flags & SWMWF_INSERTED)) { + if (ow > bounds->w) { + DFBRegion region = { bounds->w, 0, ow - 1, MIN(bounds->h, oh) - 1 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + + if (oh > bounds->h) { + DFBRegion region = { 0, bounds->h, MAX(bounds->w, ow) - 1, oh - 1 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + } + + /* Send new size */ + if (!(window->config.options & DWOP_SCALE)) { + evt.type = DWET_SIZE; + evt.w = bounds->w; + evt.h = bounds->h; + + sawman_post_event( sawman, sawwin, &evt ); + } + + return DFB_OK; +} + +static DFBResult +set_window_bounds( SaWMan *sawman, + SaWManWindow *sawwin, + WMData *wm_data, + int x, + int y, + int width, + int height ) +{ + DFBResult ret; + DFBWindowEvent evt; + DFBRegion old_region; + DFBRegion new_region; + DFBRectangle *bounds; + CoreWindow *window; + + D_DEBUG_AT( SaWMan_WM, "%s( %p [%d] %d, %d - %dx%d )\n", __FUNCTION__, sawwin, sawwin->id, x, y, width, height ); + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( width > 0 ); + D_ASSERT( height > 0 ); + + if (width > 4096 || height > 4096) + return DFB_LIMITEXCEEDED; + + window = sawwin->window; + D_ASSERT( window != NULL ); + + /* Resize the surface? */ + if (window->surface && !(window->config.options & DWOP_SCALE)) { + ret = dfb_surface_reformat( window->surface, + width, height, window->surface->config.format ); + if (ret) + return ret; + } + + bounds = &window->config.bounds; + + old_region.x1 = bounds->x - x; + old_region.y1 = bounds->y - y; + old_region.x2 = old_region.x1 + bounds->w - 1; + old_region.y2 = old_region.y1 + bounds->h - 1; + + bounds->x = x; + bounds->y = y; + bounds->w = width; + bounds->h = height; + + new_region.x1 = 0; + new_region.y1 = 0; + new_region.x2 = width - 1; + new_region.y2 = height - 1; + + if (!dfb_region_region_intersect( &window->config.opaque, &new_region )) + window->config.opaque = new_region; + + /* Update exposed area. */ + if (SAWMAN_VISIBLE_WINDOW( window ) && (sawwin->flags & SWMWF_INSERTED)) { + if (dfb_region_region_intersect( &new_region, &old_region )) { + /* left */ + if (new_region.x1 > old_region.x1) { + DFBRegion region = { old_region.x1, old_region.y1, + new_region.x1 - 1, new_region.y2 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + + /* upper */ + if (new_region.y1 > old_region.y1) { + DFBRegion region = { old_region.x1, old_region.y1, + old_region.x2, new_region.y1 - 1 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + + /* right */ + if (new_region.x2 < old_region.x2) { + DFBRegion region = { new_region.x2 + 1, new_region.y1, + old_region.x2, new_region.y2 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + + /* lower */ + if (new_region.y2 < old_region.y2) { + DFBRegion region = { old_region.x1, new_region.y2 + 1, + old_region.x2, old_region.y2 }; + + sawman_update_window( sawman, sawwin, ®ion, 0, SWMUF_UPDATE_BORDER ); + } + } + else + sawman_update_window( sawman, sawwin, &old_region, 0, SWMUF_UPDATE_BORDER ); + } + + /* Send new position and size */ + evt.type = DWET_POSITION_SIZE; + evt.x = bounds->x; + evt.y = bounds->y; + evt.w = bounds->w; + evt.h = bounds->h; + + sawman_post_event( sawman, sawwin, &evt ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +grab_keyboard( SaWMan *sawman, + SaWManWindow *sawwin ) +{ + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + if (sawman->keyboard_window) + return DFB_LOCKED; + + sawman->keyboard_window = sawwin; + + return DFB_OK; +} + +static DFBResult +ungrab_keyboard( SaWMan *sawman, + SaWManWindow *sawwin ) +{ + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + if (sawman->keyboard_window == sawwin) + sawman->keyboard_window = NULL; + + return DFB_OK; +} + +static DFBResult +grab_pointer( SaWMan *sawman, + SaWManWindow *sawwin ) +{ + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + if (sawman->pointer_window) + return DFB_LOCKED; + + sawman->pointer_window = sawwin; + + return DFB_OK; +} + +static DFBResult +ungrab_pointer( SaWMan *sawman, + SaWManWindow *sawwin ) +{ + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + if (sawman->pointer_window == sawwin) + sawman->pointer_window = NULL; + + return DFB_OK; +} + +static DFBResult +grab_key( SaWMan *sawman, + SaWManWindow *sawwin, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ) +{ + int i; + StackData *data; + SaWManGrabbedKey *key; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + data = sawwin->stack_data; + D_MAGIC_ASSERT( data, StackData ); + + /* Reject if already grabbed. */ + direct_list_foreach (key, sawman->grabbed_keys) + if (key->symbol == symbol && key->modifiers == modifiers) + return DFB_LOCKED; + + /* Allocate grab information. */ + key = SHCALLOC( sawwin->shmpool, 1, sizeof(SaWManGrabbedKey) ); + + /* Fill grab information. */ + key->symbol = symbol; + key->modifiers = modifiers; + key->owner = sawwin; + + /* Add to list of key grabs. */ + direct_list_append( &sawman->grabbed_keys, &key->link ); + + /* Remove implicit grabs for this key. */ + for (i=0; ikeys[i].code != -1 && sawman->keys[i].symbol == symbol) + sawman->keys[i].code = -1; + + return DFB_OK; +} + +static DFBResult +ungrab_key( SaWMan *sawman, + SaWManWindow *sawwin, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ) +{ + StackData *data; + SaWManGrabbedKey *key; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + data = sawwin->stack_data; + D_MAGIC_ASSERT( data, StackData ); + + direct_list_foreach (key, sawman->grabbed_keys) { + if (key->symbol == symbol && key->modifiers == modifiers && key->owner == sawwin) { + direct_list_remove( &sawman->grabbed_keys, &key->link ); + SHFREE( sawwin->shmpool, key ); + return DFB_OK; + } + } + + return DFB_IDNOTFOUND; +} + +static DFBResult +request_focus( SaWMan *sawman, + SaWManWindow *sawwin ) +{ + DFBResult ret; + CoreWindowStack *stack; + SaWManWindow *entered; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + ret = sawman_switch_focus( sawman, sawwin ); + if (ret) + return ret; + + entered = sawman->entered_window; + + if (entered && entered != sawwin) { + DFBWindowEvent we; + + D_MAGIC_ASSERT( entered, SaWManWindow ); + D_ASSERT( entered->window != NULL ); + + we.type = DWET_LEAVE; + + sawman_window_get_cursor_position( sawman, stack, entered, &we.x, &we.y, &we.cx, &we.cy ); + + sawman_post_event( sawman, entered, &we ); + + sawman->entered_window = NULL; + } + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +handle_key_press( CoreWindowStack *stack, + StackData *data, + const DFBInputEvent *event ) +{ + SaWMan *sawman; + SaWManWindow *sawwin; + + D_ASSERT( stack != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_KEYPRESS ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + sawwin = get_keyboard_window( data, event ); + if (sawwin) + send_key_event( sawman, sawwin, event ); + + return DFB_OK; +} + +static DFBResult +handle_key_release( CoreWindowStack *stack, + StackData *data, + const DFBInputEvent *event ) +{ + SaWMan *sawman; + SaWManWindow *sawwin; + + D_ASSERT( stack != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_KEYRELEASE ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + sawwin = get_keyboard_window( data, event ); + if (sawwin) + send_key_event( sawman, sawwin, event ); + + return DFB_OK; +} + +static DFBResult +handle_button_press( CoreWindowStack *stack, + StackData *data, + const DFBInputEvent *event ) +{ + SaWMan *sawman; + SaWManWindow *sawwin; + + D_ASSERT( stack != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_BUTTONPRESS ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + if (!stack->cursor.enabled) + return DFB_OK; + + if (sawman->focused_window && sawman->focused_window->window->config.cursor_flags & DWCF_EXPLICIT) + sawwin = sawman->focused_window; + else if (sawman->pointer_window) + sawwin = sawman->pointer_window; + else { + sawwin = sawman->entered_window; + } + + if (sawwin) + send_button_event( sawman, sawwin, stack, event ); + + return DFB_OK; +} + +static DFBResult +handle_button_release( CoreWindowStack *stack, + StackData *data, + const DFBInputEvent *event ) +{ + SaWMan *sawman; + SaWManWindow *sawwin; + + D_ASSERT( stack != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_BUTTONRELEASE ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + if (!stack->cursor.enabled) + return DFB_OK; + + if (sawman->focused_window && sawman->focused_window->window->config.cursor_flags & DWCF_EXPLICIT) + sawwin = sawman->focused_window; + else if (sawman->pointer_window) + sawwin = sawman->pointer_window; + else { + sawwin = sawman->entered_window; + } + + if (sawwin) + send_button_event( sawman, sawwin, stack, event ); + + return DFB_OK; +} + +static void +post_motion_event( SaWMan *sawman, + SaWManWindow *sawwin, + int x, // SaWMan coordinates + int y, + DFBWindowEventFlags flags ) +{ + SaWManTier *tier; + DFBWindowEvent we; + int cx, cy; + int sx, sy; + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %d,%d, 0x%04x )\n", __FUNCTION__, sawman, sawwin, x, y, flags ); + + D_MAGIC_ASSERT( sawman, SaWMan ); + 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 ); + + D_DEBUG_AT( SaWMan_WM, " -> Tier with resolution %dx%d\n", tier->size.w, tier->size.h ); + + /* 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; + + D_DEBUG_AT( SaWMan_WM, " => %d, %d\n", cx, cy ); + + /* Subtract offset of Window within layout (tier coordinates) */ + if (!(flags & DWEF_RELATIVE)) { + D_DEBUG_AT( SaWMan_WM, " -> Window at offset %d,%d\n", sawwin->dst.x, sawwin->dst.y ); + + x = cx - sawwin->dst.x; + y = cy - sawwin->dst.y; + + D_DEBUG_AT( SaWMan_WM, " => %d, %d\n", x, y ); + } + else { + x = cx; + y = cy; + } + + sx = sawwin->window->config.cursor_resolution.w ?: sawwin->src.w; + sy = sawwin->window->config.cursor_resolution.h ?: sawwin->src.h; + + D_DEBUG_AT( SaWMan_WM, " -> Window with scaling %dx%d -> %dx%d\n", sawwin->dst.w, sawwin->dst.h, sx, sy ); + + /* Convert to Window coordinates */ + x = x * sx / sawwin->dst.w; + y = y * sy / sawwin->dst.h; + + D_DEBUG_AT( SaWMan_WM, " => %d, %d\n", x, y ); + + /* Fill event structure */ + we.type = DWET_MOTION; + we.flags = flags; + we.x = x; + we.y = y; + we.cx = cx; + we.cy = cy; + + sawman_post_event( sawman, sawwin, &we ); +} + +static void +handle_motion( CoreWindowStack *stack, + SaWMan *sawman, + int dx, + int dy ) +{ + SaWManWindow *sawwin = NULL; + DFBWindowCursorFlags flags = DWCF_NONE; + int cx, cy; + + D_ASSERT( stack != NULL ); + D_MAGIC_ASSERT( sawman, SaWMan ); + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %d,%d )\n", __FUNCTION__, stack, sawman, dx, dy ); + D_DEBUG_AT( SaWMan_WM, " -> SaWMan with resolution %dx%d\n", sawman->resolution.w, sawman->resolution.h ); + + if (!stack->cursor.enabled) + return; + + + cx = stack->cursor.x + dx; + cy = stack->cursor.y + dy; + + + if (sawman->focused_window && sawman->focused_window->window->config.cursor_flags & DWCF_EXPLICIT) + sawwin = sawman->focused_window; + else if (sawman->pointer_window) + sawwin = sawman->pointer_window; + else { + sawman_update_focus( sawman, stack, cx, cy ); + + sawwin = sawman->entered_window; + } + + if (sawwin) + flags = sawwin->window->config.cursor_flags; + + if (flags & DWCF_TRAPPED) { + SaWManTier *tier; + + int x1 = sawwin->dst.x; + int y1 = sawwin->dst.y; + int x2 = sawwin->dst.x + sawwin->dst.w; + int y2 = sawwin->dst.y + sawwin->dst.h; + + /* Retrieve corresponding SaWManTier. */ + tier = sawman_tier_by_class( sawman, sawwin->window->config.stacking ); + D_MAGIC_ASSERT( tier, SaWManTier ); + + D_DEBUG_AT( SaWMan_WM, " -> Tier with resolution %dx%d\n", tier->size.w, tier->size.h ); + + D_DEBUG_AT( SaWMan_WM, " -> Trapping in %d,%d-%dx%d\n", x1, y1, x2 - x1, y2 - y1 ); + + x1 = (s64) x1 * (s64) sawman_config->resolution.w / (s64) tier->size.w; + y1 = (s64) y1 * (s64) sawman_config->resolution.h / (s64) tier->size.h; + x2 = (s64) x2 * (s64) sawman_config->resolution.w / (s64) tier->size.w; + y2 = (s64) y2 * (s64) sawman_config->resolution.h / (s64) tier->size.h; + + D_DEBUG_AT( SaWMan_WM, " -> Scaled to %d,%d-%dx%d\n", x1, y1, x2 - x1, y2 - y1 ); + + if (cx < x1) + cx = x1; + else if (cx > x2) + cx = x2; + + if (cy < y1) + cy = y1; + else if (cy > y2) + cy = y2; + + D_DEBUG_AT( SaWMan_WM, " -> Cursor trapped at %d,%d\n", cx, cy ); + } + + if (flags & DWCF_UNCLIPPED) + { + D_DEBUG_AT( SaWMan_WM, " -> Cursor unclipped at %d,%d\n", cx, cy ); + } + else { + 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; + + D_DEBUG_AT( SaWMan_WM, " -> Cursor clipped at %d,%d\n", cx, cy ); + } + + + if (flags & DWCF_FIXED) + D_DEBUG_AT( SaWMan_WM, " -> Cursor is fixed at %d,%d\n", stack->cursor.x, stack->cursor.y ); + else if (cx != stack->cursor.x || cy != stack->cursor.y) { + D_DEBUG_AT( SaWMan_WM, " -> Cursor moved %d,%d -> %d,%d\n", stack->cursor.x, stack->cursor.y, cx, cy ); + + stack->cursor.x = cx; + stack->cursor.y = cy; + + dfb_wm_update_cursor( stack, CCUF_POSITION ); + } + + + if (sawwin) { + if (flags & DWCF_RELATIVE) + post_motion_event( sawman, sawwin, dx, dy, DWEF_RELATIVE ); + else + post_motion_event( sawman, sawwin, cx, cy, DWEF_NONE ); + } +} + +static void +handle_wheel( CoreWindowStack *stack, + SaWMan *sawman, + int dz ) +{ + DFBWindowEvent we; + SaWManWindow *sawwin; + + D_ASSERT( stack != NULL ); + D_MAGIC_ASSERT( sawman, SaWMan ); + + if (!stack->cursor.enabled) + return; + + if (sawman->focused_window && sawman->focused_window->window->config.cursor_flags & DWCF_EXPLICIT) + sawwin = sawman->focused_window; + else if (sawman->pointer_window) + sawwin = sawman->pointer_window; + else { + sawwin = sawman->entered_window; + } + + if (sawwin) { + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_ASSERT( sawwin->window != NULL ); + + we.type = DWET_WHEEL; + we.step = dz; + + sawman_window_get_cursor_position( sawman, stack, sawwin, &we.x, &we.y, &we.cx, &we.cy ); + + sawman_post_event( sawman, sawwin, &we ); + } +} + +static DFBResult +handle_axis_motion( CoreWindowStack *stack, + SaWMan *sawman, + SaWManTier *tier, + const DFBInputEvent *event ) +{ + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p )\n", __FUNCTION__, stack, sawman ); + + D_ASSERT( stack != NULL ); + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( tier, SaWManTier ); + D_ASSERT( event != NULL ); + D_ASSERT( event->type == DIET_AXISMOTION ); + + if (event->flags & DIEF_AXISREL) { + int rel = event->axisrel; + + /* handle cursor acceleration */ + if (rel > stack->cursor.threshold) + rel += (rel - stack->cursor.threshold) + * stack->cursor.numerator + / stack->cursor.denominator; + else if (rel < -stack->cursor.threshold) + rel += (rel + stack->cursor.threshold) + * stack->cursor.numerator + / stack->cursor.denominator; + + switch (event->axis) { + case DIAI_X: + sawman->cursor.dx += rel; + break; + + case DIAI_Y: + sawman->cursor.dy += rel; + break; + + case DIAI_Z: + handle_wheel( stack, sawman, - event->axisrel ); + break; + + default: + ; + } + } + else if (event->flags & DIEF_AXISABS) { + int axismin = 0; + int axisabs = event->axisabs; + + if (event->flags & DIEF_MIN) { + axismin = event->min; + + axisabs -= axismin; + } + + switch (event->axis) { + case DIAI_X: + if (event->flags & DIEF_MAX) + axisabs = (s64) axisabs * (s64) sawman->resolution.w / (s64) (event->max - axismin + 1); + + sawman->cursor.dx = axisabs - stack->cursor.x; + break; + + case DIAI_Y: + if (event->flags & DIEF_MAX) + axisabs = (s64) axisabs * (s64) sawman->resolution.h / (s64) (event->max - axismin + 1); + + sawman->cursor.dy = axisabs - stack->cursor.y; + break; + + default: + ; + } + } + + if (!(event->flags & DIEF_FOLLOW) && (sawman->cursor.dx || sawman->cursor.dy)) { + handle_motion( stack, sawman, sawman->cursor.dx, sawman->cursor.dy ); + + sawman->cursor.dx = 0; + sawman->cursor.dy = 0; + } + + return DFB_OK; +} + +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ + +static void +wm_get_info( CoreWMInfo *info ) +{ + info->version.major = 0; + info->version.minor = 2; + info->version.binary = 1; + + snprintf( info->name, DFB_CORE_WM_INFO_NAME_LENGTH, "SaWMan" ); + snprintf( info->vendor, DFB_CORE_WM_INFO_VENDOR_LENGTH, "directfb.org" ); + + info->wm_data_size = sizeof(WMData); + info->wm_shared_size = sizeof(SaWMan); + info->stack_data_size = sizeof(StackData); + info->window_data_size = sizeof(SaWManWindow); +} + +static DFBResult +wm_initialize( CoreDFB *core, void *wm_data, void *shared_data ) +{ + WMData *data = wm_data; + SaWMan *sawman = shared_data; + + data->core = core; + data->world = dfb_core_world( core ); + data->sawman = sawman; + + sawman_config_init( NULL, NULL ); + + return sawman_initialize( sawman, data->world, &data->process ); +} + +static DFBResult +wm_join( CoreDFB *core, void *wm_data, void *shared_data ) +{ + WMData *data = wm_data; + SaWMan *sawman = shared_data; + + data->core = core; + data->world = dfb_core_world( core ); + data->sawman = sawman; + + sawman_config_init( NULL, NULL ); + + return sawman_join( sawman, data->world, &data->process ); +} + +static DFBResult +wm_shutdown( bool emergency, void *wm_data, void *shared_data ) +{ + WMData *data = wm_data; + SaWMan *sawman = shared_data; + + return sawman_shutdown( sawman, data->world ); +} + +static DFBResult +wm_leave( bool emergency, void *wm_data, void *shared_data ) +{ + WMData *data = wm_data; + SaWMan *sawman = shared_data; + + return sawman_leave( sawman, data->world ); +} + +static DFBResult +wm_suspend( void *wm_data, void *shared_data ) +{ + return DFB_OK; +} + +static DFBResult +wm_resume( void *wm_data, void *shared_data ) +{ + return DFB_OK; +} + +static DFBResult +wm_post_init( void *wm_data, void *shared_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman = shared_data; + SaWManTier *tier; + + D_ASSERT( wm_data != NULL ); + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + sawman_post_init( sawman, wmdata->world ); + + direct_list_foreach (tier, sawman->tiers) { + const SaWManBorderInit *border; + + D_MAGIC_ASSERT( tier, SaWManTier ); + + tier->context->lock = sawman->lock; + + ret = dfb_layer_context_get_configuration( tier->context, &tier->config ); + if (ret) + D_DERROR( ret, "SaWMan/PostInit: Could not get configuration of layer context!\n" ); + + D_INFO( "SaWMan/Init: Layer %d: %dx%d, %s, options: %x\n", + tier->layer_id, tier->config.width, tier->config.height, + dfb_pixelformat_name( tier->config.pixelformat ), tier->config.options ); + + + border = &sawman_config->borders[(tier->classes & SWMSC_LOWER) ? 0 : + (tier->classes & SWMSC_MIDDLE) ? 1 : 2]; + + tier->border_config = tier->config; + + if (border->resolution.w && border->resolution.h) { + tier->border_config.width = border->resolution.w; + tier->border_config.height = border->resolution.h; + } + + if (border->format) + tier->border_config.pixelformat = border->format; + + tier->border_config.options = DLOP_SRC_COLORKEY; + + D_INFO( "SaWMan/Init: Border %d: %dx%d, %s, options: %x\n", + tier->layer_id, tier->border_config.width, tier->border_config.height, + dfb_pixelformat_name( tier->border_config.pixelformat ), tier->border_config.options ); + } + + sawman_process_updates( sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_init_stack( CoreWindowStack *stack, + void *wm_data, + void *stack_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + CoreLayerContext *context; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + context = stack->context; + D_ASSERT( context != NULL ); + D_ASSERT( context->config.pixelformat != DSPF_UNKNOWN ); + D_ASSERT( context->config.width > 0 ); + D_ASSERT( context->config.height > 0 ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + data->stack = stack; + data->sawman = sawman; + + D_MAGIC_SET( data, StackData ); + + if (!sawman_tier_by_layer( sawman, context->layer_id, &tier ) || tier->stack) { + sawman_unlock( sawman ); + return DFB_OK; + } + + D_INFO( "SaWMan: Initializing stack %p for tier %p, %dx%d, layer %d, context %p [%d]...\n", + stack, tier, stack->width, stack->height, context->layer_id, context, context->object.ref.multi.id ); + + tier->stack = stack; + tier->context = context; + tier->size.w = stack->width; + tier->size.h = stack->height; + + ret = dfb_layer_context_get_primary_region( context, true, &tier->region ); + if (ret) { + sawman_unlock( sawman ); + D_MAGIC_CLEAR( data ); + return ret; + } + + dfb_layer_region_globalize( tier->region ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_close_stack( CoreWindowStack *stack, + void *wm_data, + void *stack_data ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_OK; + } + + D_ASSERT( tier->context != NULL ); + + tier->stack = NULL; + tier->context = NULL; + tier->size.w = 0; + tier->size.h = 0; + + dfb_layer_region_unlink( &tier->region ); + + /* Destroy backing store of software cursor. */ + if (tier->cursor_bs) + dfb_surface_unlink( &tier->cursor_bs ); + + direct_list_remove( &sawman->tiers, &tier->link ); + D_MAGIC_CLEAR( tier ); + SHFREE( sawman->shmpool, tier ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +wm_set_active( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + bool active ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %s )\n", __FUNCTION__, + stack, wm_data, stack_data, active ? "active" : "inactive" ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_OK; + } + + + data->active = active; + + sawman_unlock( sawman ); + + if (active) + return dfb_windowstack_repaint_all( stack ); + else { + tier->active = false; + tier->single_mode = false; + tier->single_window = NULL; + } + + /* Force release of all pressed keys. */ + return wm_flush_keys( stack, wm_data, stack_data ); +} + +static DFBResult +wm_resize_stack( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int width, + int height ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %dx%d )\n", __FUNCTION__, + stack, wm_data, stack_data, width, height ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier ) || tier->single_mode) { + sawman_unlock( sawman ); + return DFB_OK; + } + + tier->size.w = width; + tier->size.h = height; + + sawman_call( sawman, SWMCID_STACK_RESIZED, &tier->size ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_process_input( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBInputEvent *event ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( stack->context != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( event != NULL ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + + D_DEBUG_AT( SaWMan_WM, "%s( device %d, type 0x%08x, flags 0x%08x )...\n", + __FUNCTION__, event->device_id, event->type, event->flags ); + + if (stack->context->layer_id != DLID_PRIMARY) + return DFB_OK; + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (sawman->cursor.context && stack == sawman->cursor.context->stack) { + direct_list_foreach (tier, sawman->tiers) { + if (tier->layer_id == sawman->cursor.context->layer_id) + break; + } + + if (!tier) { + D_DEBUG_AT( SaWMan_WM, " -> cursor tier not found!\n" ); + sawman_unlock( sawman ); + return DFB_OK; + } + + stack = tier->stack; + } + else if (!sawman_tier_by_stack( sawman, stack, &tier ) || tier != (SaWManTier*)sawman->tiers) { + D_DEBUG_AT( SaWMan_WM, " -> not for me\n" ); + sawman_unlock( sawman ); + return DFB_OK; + } + + /* FIXME: handle multiple devices */ + if (event->flags & DIEF_BUTTONS) + sawman->buttons = event->buttons; + + if (event->flags & DIEF_MODIFIERS) + sawman->modifiers = event->modifiers; + + if (event->flags & DIEF_LOCKS) + sawman->locks = event->locks; + + + /* Store event in shared memory. */ + sawman->manager.event = *event; + + /* Call application manager executable. */ + ret = sawman_call( sawman, SWMCID_INPUT_FILTER, &sawman->manager.event ); + + sawman_process_updates( sawman, DSFLIP_NONE ); + + switch (ret) { + case DFB_OK: + event = &sawman->manager.event; + break; + + case DFB_NOIMPL: + break; + + default: + /* filtered out */ + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; + } + + switch (event->type) { + case DIET_KEYPRESS: + ret = handle_key_press( stack, data, event ); + break; + + case DIET_KEYRELEASE: + ret = handle_key_release( stack, data, event ); + break; + + case DIET_BUTTONPRESS: + ret = handle_button_press( stack, data, event ); + break; + + case DIET_BUTTONRELEASE: + ret = handle_button_release( stack, data, event ); + break; + + case DIET_AXISMOTION: + ret = handle_axis_motion( stack, sawman, tier, event ); + break; + + default: + D_ONCE( "unknown input event type" ); + ret = DFB_UNSUPPORTED; + break; + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_flush_keys( CoreWindowStack *stack, + void *wm_data, + void *stack_data ) +{ + int i; + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_OK; + } + + for (i=0; ikeys[i].code != -1) { + DFBWindowEvent we; + + we.type = DWET_KEYUP; + we.flags = 0; + 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, sawman->keys[i].owner, &we ); + + sawman->keys[i].code = -1; + } + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_window_at( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int x, + int y, + CoreWindow **ret_window ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManWindow *sawwin; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( ret_window != NULL ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + sawwin = sawman_window_at_pointer( data->sawman, stack, x, y ); + + *ret_window = sawwin ? sawwin->window : NULL; + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_window_lookup( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + DFBWindowID window_id, + CoreWindow **ret_window ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManWindow *window; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( ret_window != NULL ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + direct_list_foreach (window, sawman->windows) { + D_MAGIC_ASSERT( window, SaWManWindow ); + + if (window->id == window_id) + break; + } + + if (window) { + D_ASSERT( window->window != NULL ); + + *ret_window = window->window; + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return window ? DFB_OK : DFB_ITEMNOTFOUND; +} + +static DFBResult +wm_enum_windows( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWMWindowCallback callback, + void *callback_ctx ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManWindow *window; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( callback != NULL ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + direct_list_foreach (window, sawman->windows) { + D_MAGIC_ASSERT( window, SaWManWindow ); + D_ASSERT( window->window != NULL ); + + if (callback( window->window, callback_ctx ) != DFENUM_OK) + break; + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_get_insets( CoreWindowStack *stack, + CoreWindow *window, + DFBInsets *insets ) +{ + insets->l = 0; + insets->t = 0; + insets->r = 0; + insets->b = 0; + + return DFB_OK; +} + + +static DFBResult +wm_preconfigure_window( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManTier *tier; + SaWManWindow *sawwin = window_data; + + SaWManWindowInfo *info; + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %p, %p )\n", __FUNCTION__, + stack, wm_data, stack_data, window, window_data ); + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_OK; + } + + /* Override with our own ID which is unique among all tiers, not only each layer context. */ + window->id = ++sawman->window_ids; + + /* Lookup parent window. */ + if (window->config.association) { + SaWManWindow *parent = NULL; + + D_DEBUG_AT( SaWMan_WM, " -> parent win id %u\n", window->config.association ); + + direct_list_foreach (parent, sawman->windows) { + D_MAGIC_ASSERT( parent, SaWManWindow ); + D_ASSERT( parent->window != NULL ); + + if (parent->id == window->config.association) + break; + } + + if (!parent) { + D_ERROR( "SaWMan/WM: Can't find parent window with ID %d!\n", window->config.association ); + sawman_unlock( sawman ); + return DFB_IDNOTFOUND; + } + +#ifndef OLD_COREWINDOWS_STRUCTURE + if (parent->window->toplevel != window->toplevel) { + D_ERROR( "SaWMan/WM: Can't associate windows with different toplevel!\n" ); + sawman_unlock( sawman ); + return DFB_INVARG; + } +#endif + + D_DEBUG_AT( SaWMan_WM, " -> parent window %p\n", parent ); + + sawwin->parent = parent; + } + + info = &sawman->callback.info; + SAWMANWINDOWCONFIG_COPY( &info->config, &window->config ) + + switch (ret = sawman_call( sawman, SWMCID_WINDOW_PRECONFIG, &info->config )) { + case DFB_OK: + break; + + case DFB_NOIMPL: + ret = DFB_OK; + break; + + default: + break; + } + + SAWMANWINDOWCONFIG_COPY( &window->config, &info->config ) + + sawman_process_updates( wmdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_set_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void *value, + void **ret_old_value ) +{ + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( key != NULL ); + + fusion_object_set_property((FusionObject*)window, + key,value,ret_old_value); + return DFB_OK; +} + +static DFBResult +wm_get_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **ret_value ) +{ + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( key != NULL ); + D_ASSERT( ret_value != NULL ); + + *ret_value = fusion_object_get_property((FusionObject*)window,key); + + return DFB_OK; +} + + +static DFBResult +wm_remove_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **ret_value ) +{ + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( key != NULL ); + + fusion_object_remove_property((FusionObject*)window,key,ret_value); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_add_window( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWManWindow *sawwin = window_data; + StackData *sdata = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + SaWManWindowInfo *info; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( window_data != NULL ); + + D_MAGIC_ASSERT( sdata, StackData ); + + sawman = sdata->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + D_ERROR( "SaWMan/WM: Cannot add window to unknown stack!\n" ); + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + /* Initialize window data. */ + sawwin->sawman = sawman; + sawwin->shmpool = sawman->shmpool; + sawwin->process = wmdata->process; + sawwin->id = window->id; + sawwin->caps = window->caps; + sawwin->window = window; + sawwin->stack = stack; + sawwin->stack_data = stack_data; + + D_MAGIC_SET( sawwin, SaWManWindow ); + + if (window->config.options & (DWOP_KEEP_ABOVE | DWOP_KEEP_UNDER)) { + if (!sawwin->parent) { + D_ERROR( "SaWMan/WM: Cannot use KEEP_ABOVE/UNDER without a parent!\n" ); + D_MAGIC_CLEAR( sawwin ); + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + if (window->config.options & DWOP_KEEP_ABOVE) { + if (sawman_window_priority(sawwin->parent) > sawman_window_priority(sawwin)) { + D_MAGIC_CLEAR( sawwin ); + sawman_unlock( sawman ); + return DFB_INVARG; + } + } + else { + if (sawman_window_priority(sawwin->parent) < sawman_window_priority(sawwin)) { + D_MAGIC_CLEAR( sawwin ); + sawman_unlock( sawman ); + return DFB_INVARG; + } + } + } + + fusion_vector_init( &sawwin->children, 2, sawwin->shmpool ); + + sawwin->priority = sawman_window_priority( sawwin ); + + direct_list_append( &sawman->windows, &sawwin->link ); + + fusion_ref_up( &sawwin->process->ref, true ); + + // + // PR brg36mgr#135330: [550r2cr1][StressStab][CRASH]Alive hotboot timeout: process = /dvbt2App, after previous crash [DTR-BC-dvbt_mix_zap] + // The problem is that amapp does an assocation in the SWMCID_WINDOW_ADDED notification call and if the following block + // of code is executed after this notification, the parent window is referenced one time too many in dfb_window_link. + // As a result the window is not removed when the application is killed on a hotboot leading to a timeout and a fast cold boot. + // The solution is to move this code before the notification call so that the association is only done when + // the CreateWindow function specifies it. + if (ret == DFB_OK && sawwin->parent) { + SaWManWindow *parent = sawwin->parent; + + D_MAGIC_ASSERT( parent, SaWManWindow ); + D_ASSERT( parent->window != NULL ); + D_ASSERT( parent->id == window->config.association ); + + 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", window->config.association ); + sawman_unlock( sawman ); + return ret; + } + + ret = fusion_vector_add( &parent->children, sawwin ); + if (ret) { + dfb_window_unlink( &sawwin->parent_window ); + sawman_unlock( sawman ); + return ret; + } + } + + /* Send notification to windows watchers */ + dfb_wm_dispatch_WindowAdd( wmdata->core, window ); + + info = &sawman->callback.info; + info->handle = (SaWManWindowHandle)sawwin; + 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); + + switch (ret = sawman_call( sawman, SWMCID_WINDOW_ADDED, info )) { + case DFB_OK: + break; + + case DFB_NOIMPL: + /* Actually add the window to the stack. */ + ret = sawman_insert_window( sawman, sawwin, NULL, true ); + break; + + default: + direct_list_remove( &sawman->windows, &sawwin->link ); + break; + } + + sawman_update_geometry( sawwin ); + + sawman_process_updates( wmdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_remove_window( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWManWindow *sawwin = window_data; + StackData *sdata = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + SaWManWindowInfo *info; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( window_data != NULL ); + + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + D_MAGIC_ASSERT( sdata, StackData ); + + sawman = sdata->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Check for valid stack. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + D_ERROR( "SaWMan/WM: Cannot remove window from unknown stack!\n" ); + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + /* Retrieve corresponding SaWManTier. */ + tier = sawman_tier_by_class( sawman, window->config.stacking ); + if (!tier) { + sawman_unlock( sawman ); + return DFB_BUG; + } + + direct_list_remove( &sawman->windows, &sawwin->link ); + + info = &sawman->callback.info; + info->handle = (SaWManWindowHandle)sawwin; + 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); + + switch (ret = sawman_call( sawman, SWMCID_WINDOW_REMOVED, info )) { + case DFB_NOIMPL: + ret = DFB_OK; + + case DFB_OK: + D_ASSERT( sawwin->children.count == 0 ); + + /* Actually remove the window from the stack. */ + if (sawwin->flags & SWMWF_INSERTED) + sawman_remove_window( sawman, sawwin ); + else + sawman_withdraw_window(sawman,sawwin); // NDC - otherwise we have issues when focus is switched after window deletion + + /* Remove from parent window. */ + if (sawwin->parent) { + SaWManWindow *parent = sawwin->parent; + + D_MAGIC_ASSERT( parent, SaWManWindow ); + + fusion_vector_remove( &parent->children, fusion_vector_index_of( &parent->children, sawwin ) ); + sawwin->parent = NULL; + + dfb_window_unlink( &sawwin->parent_window ); + } + + fusion_ref_down( &sawwin->process->ref, true ); + + D_MAGIC_CLEAR( sawwin ); + break; + + default: + direct_list_append( &sawman->windows, &sawwin->link ); + break; + } + + if (tier->single_window == sawwin) + tier->single_window = NULL; + + /* Send notification to windows watchers */ + dfb_wm_dispatch_WindowRemove( wmdata->core, window ); + + sawman_process_updates( sdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_set_window_config( CoreWindow *window, + void *wm_data, + void *window_data, + const CoreWindowConfig *updated, + CoreWindowConfigFlags flags ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManWindow *sawwin = window_data; + SaWManTier *tier; + CoreWindowStack *stack; + + SaWManWindowConfig *config; + SaWManWindowConfig *current; + SaWManWindowReconfig *reconfig; + + DFBInputDeviceKeySymbol *shared_keys = 0; + + D_DEBUG_AT( SaWMan_WM, "%s( window %p, flags 0x%08x )\n", __FUNCTION__, window, flags ); + + D_ASSERT( window != NULL ); + D_ASSERT( window->stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( updated != NULL ); + + sawman = wmdata->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + if ((flags & CWCF_OPTIONS) && (updated->options & (DWOP_KEEP_ABOVE | DWOP_KEEP_UNDER))) { + if (!sawwin->parent) + return DFB_UNSUPPORTED; + + if (updated->options & DWOP_KEEP_ABOVE) { + if (sawman_window_priority(sawwin->parent) > sawman_window_priority(sawwin)) + return DFB_INVARG; + } + else { + if (sawman_window_priority(sawwin->parent) < sawman_window_priority(sawwin)) + return DFB_INVARG; + } + } + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + reconfig = &sawman->callback.reconfig; + + reconfig->caps = sawwin->caps; + reconfig->handle = (SaWManWindowHandle)sawwin; + + current = &reconfig->current; + config = &reconfig->request; + + SAWMANWINDOWCONFIG_COPY( current, &window->config ) + *config = *current; /* make sure that all fields in "request" are valid */ + SAWMANWINDOWCONFIG_COPY_IF( config, updated, flags ) + + reconfig->flags = 0; + + /* special consideration due to possibility of local pointer in request */ + current->key_selection = window->config.key_selection; + current->keys = window->config.keys; + current->num_keys = window->config.num_keys; + if( flags & CWCF_KEY_SELECTION ) + { + config->key_selection = updated->key_selection; + config->keys = 0; + config->num_keys = updated->num_keys; + + if( config->key_selection == DWKS_LIST ) { + unsigned int bytes = sizeof(DFBInputDeviceKeySymbol) * config->num_keys; + shared_keys = SHMALLOC( sawwin->shmpool, bytes ); + if (!shared_keys) { + D_ERROR( "SaWMan/WM: Could not allocate %d bytes for list " + "of selected keys (%d)!\n", bytes, config->num_keys ); + return D_OOSHM(); + } + config->keys = shared_keys; + direct_memcpy( config->keys, updated->keys, bytes ); + } + + /* ..and add the flag */ + reconfig->flags = SWMCF_KEY_SELECTION; + } + + reconfig->flags = + (flags & CWCF_POSITION ? SWMCF_POSITION : 0) + | (flags & CWCF_SIZE ? SWMCF_SIZE : 0) + | (flags & CWCF_OPACITY ? SWMCF_OPACITY : 0) + | (flags & CWCF_STACKING ? SWMCF_STACKING : 0) + | (flags & CWCF_OPTIONS ? SWMCF_OPTIONS : 0) + | (flags & CWCF_EVENTS ? SWMCF_EVENTS : 0) + | (flags & CWCF_COLOR ? SWMCF_COLOR : 0) + | (flags & CWCF_COLOR_KEY ? SWMCF_COLOR_KEY : 0) + | (flags & CWCF_OPAQUE ? SWMCF_OPAQUE : 0) + | (flags & CWCF_ASSOCIATION ? SWMCF_ASSOCIATION : 0) + | (flags & CWCF_CURSOR_FLAGS ? SWMCF_CURSOR_FLAGS : 0) + | (flags & CWCF_CURSOR_RESOLUTION ? SWMCF_CURSOR_RESOLUTION : 0) + | (flags & CWCF_SRC_GEOMETRY ? SWMCF_SRC_GEOMETRY : 0) + | (flags & CWCF_DST_GEOMETRY ? SWMCF_DST_GEOMETRY : 0); + + switch (ret = sawman_call( sawman, SWMCID_WINDOW_RECONFIG, reconfig )) { + case DFB_OK: { + SaWManWindowConfigFlags f = reconfig->flags; + flags = + ( flags & ~( CWCF_POSITION + | CWCF_SIZE + | CWCF_OPACITY + | CWCF_STACKING + | CWCF_OPTIONS + | CWCF_EVENTS + | CWCF_COLOR + | CWCF_COLOR_KEY + | CWCF_OPAQUE + | CWCF_ASSOCIATION + | CWCF_KEY_SELECTION + | CWCF_SRC_GEOMETRY + | CWCF_DST_GEOMETRY ) ) + | (f & SWMCF_POSITION ? CWCF_POSITION : 0) + | (f & SWMCF_SIZE ? CWCF_SIZE : 0) + | (f & SWMCF_OPACITY ? CWCF_OPACITY : 0) + | (f & SWMCF_STACKING ? CWCF_STACKING : 0) + | (f & SWMCF_OPTIONS ? CWCF_OPTIONS : 0) + | (f & SWMCF_EVENTS ? CWCF_EVENTS : 0) + | (f & SWMCF_COLOR ? CWCF_COLOR : 0) + | (f & SWMCF_COLOR_KEY ? CWCF_COLOR_KEY : 0) + | (f & SWMCF_KEY_SELECTION? CWCF_KEY_SELECTION: 0) + | (f & SWMCF_OPAQUE ? CWCF_OPAQUE : 0) + | (f & SWMCF_ASSOCIATION ? CWCF_ASSOCIATION : 0) + | (f & SWMCF_CURSOR_FLAGS ? CWCF_CURSOR_FLAGS : 0) + | (f & SWMCF_CURSOR_RESOLUTION ? CWCF_CURSOR_RESOLUTION : 0) + | (f & SWMCF_SRC_GEOMETRY ? CWCF_SRC_GEOMETRY : 0) + | (f & SWMCF_DST_GEOMETRY ? CWCF_DST_GEOMETRY : 0); + } + break; + + case DFB_NOIMPL: + break; + + default: + sawman_unlock( sawman ); + return ret; + } + + if (flags & CWCF_OPTIONS) { + if ((window->config.options & DWOP_SCALE) && !(config->options & DWOP_SCALE) && window->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/Default: 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 ); + sawman_unlock( sawman ); + 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 ); + } + + if ( (config->options ^ window->config.options) & DWOP_INPUTONLY ) { + window->config.options = config->options; + sawman_update_window( sawman, sawwin, NULL, DSFLIP_NONE, SWMUF_NONE ); + } + + 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_OPACITY && !config->opacity) + sawman_set_opacity( sawman, sawwin, config->opacity ); + + if (flags == (CWCF_POSITION | CWCF_SIZE)) { + ret = set_window_bounds( sawman, sawwin, wm_data, + config->bounds.x, config->bounds.y, + config->bounds.w, config->bounds.h); + if (ret) { + sawman_unlock( sawman ); + return ret; + } + } + else { + if (flags & CWCF_POSITION) { + ret = move_window( sawman, sawwin, + config->bounds.x - window->config.bounds.x, + config->bounds.y - window->config.bounds.y ); + if (ret) { + sawman_unlock( sawman ); + return ret; + } + } + + if (flags & CWCF_SIZE) { + ret = resize_window( sawman, sawwin, wm_data, config->bounds.w, config->bounds.h ); + if (ret) { + sawman_unlock( sawman ); + return ret; + } + } + } + + if (flags & CWCF_STACKING) + sawman_restack_window( sawman, sawwin, sawwin, 0, config->stacking ); + + if (flags & CWCF_OPACITY && config->opacity) { + sawman_set_opacity( sawman, sawwin, config->opacity ); + + /* Possibly switch focus to window now under the cursor */ + sawman_update_focus( sawman, stack, stack->cursor.x, stack->cursor.y ); + } + + if (flags & CWCF_KEY_SELECTION) { + if (config->key_selection == DWKS_LIST) { + unsigned int bytes = sizeof(DFBInputDeviceKeySymbol) * config->num_keys; + DFBInputDeviceKeySymbol *keys = config->keys; + + D_ASSERT( config->keys != NULL ); + D_ASSERT( config->num_keys > 0 ); + + if( shared_keys != config->keys) { + /* buffer difference, MUST reserve new area */ + + /* If old request buffer: must free */ + if( shared_keys ) + SHFREE( sawwin->shmpool, shared_keys ); + + keys = SHMALLOC( sawwin->shmpool, bytes ); + if (!keys) { + D_ERROR( "SaWMan/WM: Could not allocate %d bytes for list " + "of selected keys (%d)!\n", bytes, config->num_keys ); + return D_OOSHM(); + } + + direct_memcpy( keys, config->keys, bytes ); + } + + /* sort always, also when buffer was reused */ + qsort( keys, config->num_keys, sizeof(DFBInputDeviceKeySymbol), keys_compare ); + + if (window->config.keys) + SHFREE( sawwin->shmpool, window->config.keys ); + + window->config.keys = keys; + window->config.num_keys = config->num_keys; + } + else if (window->config.keys) { + SHFREE( sawwin->shmpool, window->config.keys ); + + window->config.keys = NULL; + window->config.num_keys = 0; + } + + window->config.key_selection = config->key_selection; + } + + 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 & CWCF_ASSOCIATION && window->config.association != config->association) { + SaWManWindow *parent = NULL; + + /* 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_WM, " -> 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 ); + sawman_unlock( sawman ); + 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" ); + sawman_unlock( sawman ); + return DFB_INVARG; + } + + D_DEBUG_AT( SaWMan_WM, " -> 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 ); + sawman_unlock( sawman ); + return ret; + } + + ret = fusion_vector_add( &parent->children, sawwin ); + if (ret) { + dfb_window_unlink( &sawwin->parent_window ); + sawman_unlock( sawman ); + return ret; + } + + + sawwin->parent = parent; + + /* Write back new association */ + window->config.association = config->association; + } + } + + /* Update geometry? */ + if (flags & (CWCF_POSITION | CWCF_SIZE | CWCF_SRC_GEOMETRY | CWCF_DST_GEOMETRY | CWCF_ASSOCIATION)) + sawman_update_geometry( sawwin ); + + /* Update cursor flags? */ + if (flags & CWCF_CURSOR_FLAGS) + sawman_window_set_cursor_flags( sawman, sawwin, config->cursor_flags ); + + if (flags & CWCF_CURSOR_RESOLUTION) + window->config.cursor_resolution = config->cursor_resolution; + + /* Send notification to windows watchers */ + dfb_wm_dispatch_WindowConfig( wmdata->core, window, flags ); + + sawman_process_updates( sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +wm_restack_window( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWindow *relative, + void *relative_data, + int relation ) +{ + DFBResult ret; + SaWMan *sawman; + SaWManWindow *sawwin = window_data; + SaWManTier *tier; + CoreWindowStack *stack; + StackData *data; + + SaWManWindowRelation r; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + D_ASSERT( relative == NULL || relative_data != NULL ); + D_ASSERT( relative == NULL || relative == window || relation != 0); + + data = sawwin->stack_data; + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + sawman->callback.handle = (SaWManWindowHandle)sawwin; + sawman->callback.relative = (SaWManWindowHandle)relative_data; + + r = (relation==1) ? SWMWR_TOP : SWMWR_BOTTOM; + switch (ret = sawman_call( sawman, SWMCID_WINDOW_RESTACK, (void*)r ) ) { + case DFB_OK: + case DFB_NOIMPL: + break; + + default: + sawman_unlock( sawman ); + return ret; + } + + ret = sawman_restack_window( sawman, sawwin, relative_data, relation, window->config.stacking ); + if (ret) { + sawman_unlock( sawman ); + return ret; + } + + /* Possibly switch focus to window now under the cursor */ + sawman_update_focus( sawman, stack, stack->cursor.x, stack->cursor.y ); + + sawman_process_updates( data->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_grab( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManTier *tier; + SaWManWindow *sawwin = window_data; + CoreWindowStack *stack; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( grab != NULL ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + switch (grab->target) { + case CWMGT_KEYBOARD: + ret = grab_keyboard( wmdata->sawman, window_data ); + break; + + case CWMGT_POINTER: + ret = grab_pointer( wmdata->sawman, window_data ); + break; + + case CWMGT_KEY: + ret = grab_key( wmdata->sawman, window_data, grab->symbol, grab->modifiers ); + break; + + case CWMGT_UNSELECTED_KEYS: + if (sawman->unselkeys_window) + ret = DFB_LOCKED; + else + sawman->unselkeys_window = sawwin; + + break; + + default: + D_BUG( "unknown grab target" ); + ret = DFB_BUG; + } + + sawman_process_updates( wmdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_ungrab( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManTier *tier; + SaWManWindow *sawwin = window_data; + CoreWindowStack *stack; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_ASSERT( grab != NULL ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + switch (grab->target) { + case CWMGT_KEYBOARD: + ret = ungrab_keyboard( wmdata->sawman, window_data ); + break; + + case CWMGT_POINTER: + ret = ungrab_pointer( wmdata->sawman, window_data ); + break; + + case CWMGT_KEY: + ret = ungrab_key( wmdata->sawman, window_data, grab->symbol, grab->modifiers ); + break; + + case CWMGT_UNSELECTED_KEYS: + if (sawman->unselkeys_window == sawwin) + sawman->unselkeys_window = NULL; + + default: + D_BUG( "unknown grab target" ); + ret = DFB_BUG; + } + + sawman_process_updates( wmdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_request_focus( CoreWindow *window, + void *wm_data, + void *window_data ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManTier *tier; + SaWManWindow *sawwin = window_data; + CoreWindowStack *stack; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + ret = request_focus( wmdata->sawman, window_data ); + + sawman_process_updates( wmdata->sawman, DSFLIP_NONE ); + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_begin_updates( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *update ) +{ + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManWindow *sawwin = window_data; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + D_DEBUG_AT( SaWMan_FlipOnce, "%s( %p ) <- window id %u\n", __FUNCTION__, window, window->id ); + + + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + sawwin->flags |= SWMWF_UPDATING; + sawwin->update_ms = direct_clock_get_millis(); + + + return DFB_OK; +} + +static DFBResult +wm_set_cursor_position( CoreWindow *window, + void *wm_data, + void *window_data, + int x, + int y ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManTier *tier; + SaWManWindow *sawwin = window_data; + CoreWindowStack *stack; + int sx, sy; + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %d,%d )\n", __FUNCTION__, window, wm_data, window_data, x, y ); + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + sx = sawwin->window->config.cursor_resolution.w ?: sawwin->src.w; + sy = sawwin->window->config.cursor_resolution.h ?: sawwin->src.h; + + D_DEBUG_AT( SaWMan_WM, " -> Window with scaling %dx%d -> %dx%d\n", sawwin->dst.w, sawwin->dst.h, sx, sy ); + + /* Convert to Tier coordinates */ + x = x * sawwin->dst.w / sx + sawwin->dst.x; + y = y * sawwin->dst.h / sy + sawwin->dst.y; + + D_DEBUG_AT( SaWMan_WM, " => %d, %d\n", x, y ); + + D_DEBUG_AT( SaWMan_WM, " -> Tier with resolution %dx%d\n", tier->size.w, tier->size.h ); + + /* Convert to SaWMan coordinates */ + x = (s64) x * (s64) sawman->resolution.w / (s64) tier->size.w; + y = (s64) y * (s64) sawman->resolution.h / (s64) tier->size.h; + + D_DEBUG_AT( SaWMan_WM, " => %d, %d\n", x, y ); + + if (x < 0) + x = 0; + else if (x >= sawman->resolution.w) + x = sawman->resolution.w - 1; + + if (y < 0) + y = 0; + else if (y >= sawman->resolution.h) + y = sawman->resolution.h - 1; + + D_DEBUG_AT( SaWMan_WM, " -> Cursor clipped at %d,%d\n", x, y ); + + if (x != stack->cursor.x || y != stack->cursor.y) { + D_DEBUG_AT( SaWMan_WM, " -> Cursor moved %d,%d -> %d,%d\n", stack->cursor.x, stack->cursor.y, x, y ); + + stack->cursor.x = x; + stack->cursor.y = y; + + dfb_wm_update_cursor( stack, CCUF_POSITION ); + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +/**********************************************************************************************************************/ + +static DFBResult +wm_update_stack( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret; + StackData *data = stack_data; + SaWMan *sawman; + SaWManTier *tier; + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + DFB_REGION_ASSERT( region ); + + D_MAGIC_ASSERT( data, StackData ); + + sawman = data->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %d,%d-%dx%d )\n", __FUNCTION__, + stack, wm_data, stack_data, DFB_RECTANGLE_VALS_FROM_REGION( region ) ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + if (!tier->single_mode) { + dfb_updates_add( &tier->updates, region ); + + ret = sawman_process_updates( sawman, flags ); + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return ret; +} + +static DFBResult +wm_update_window( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *region, /* surface coordinates! */ + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret; + WMData *wmdata = wm_data; + SaWMan *sawman; + SaWManWindow *sawwin = window_data; + SaWManTier *tier; + CoreWindowStack *stack; + DFBWindowEvent event; + + D_ASSERT( window != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( window_data != NULL ); + DFB_REGION_ASSERT_IF( region ); + + sawman = wmdata->sawman; + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_MAGIC_ASSERT( sawwin, SaWManWindow ); + + stack = sawwin->stack; + D_ASSERT( stack != NULL ); + + if (region) + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, %d,%d-%dx%d )\n", __FUNCTION__, + window, wm_data, window_data, DFB_RECTANGLE_VALS_FROM_REGION( region ) ); + else + D_DEBUG_AT( SaWMan_WM, "%s( %p, %p, %p, <0,0-%dx%d> )\n", __FUNCTION__, + window, wm_data, window_data, sawwin->bounds.w, sawwin->bounds.h ); + + event.flags = DWEF_NONE; + event.type = DWET_UPDATE; + event.x = region->x1; + event.y = region->y1; + event.w = region->x2 - region->x1; + event.h = region->y2 - region->y1; + + sawman_post_event( sawman, sawwin, &event ); + + if (!SAWMAN_VISIBLE_WINDOW(window)) + return DFB_OK; + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Check for window being inserted. */ + if (!(sawwin->flags & SWMWF_INSERTED)) { + D_DEBUG_AT( SaWMan_WM, " -> window %d not inserted!\n", window->id ); + sawman_unlock( sawman ); + return DFB_OK; + } + + sawwin->flags &= ~SWMWF_UPDATING; + + /* Retrieve corresponding SaWManTier. */ + tier = sawman_tier_by_class( sawman, window->config.stacking ); + if (!tier) { + D_ERROR( "SaWMan/WM: Cannot update window on unknown stack!\n" ); + sawman_unlock( sawman ); + return DFB_BUG; + } + + if (tier->single_mode && tier->single_window != NULL) { + D_ASSERT( tier->region != NULL ); + + if (tier->single_window == sawwin) { + DFBRectangle tmp = tier->single_src; + + if (!region || dfb_rectangle_intersect_by_region( &tmp, region )) { + DFBRegion reg; + DFBRectangle src = tmp; + DFBRegion cursor_visible; + + tmp.x -= tier->single_src.x; + tmp.y -= tier->single_src.y; + + D_ASSERT( window->surface != NULL ); + + dfb_gfx_copy_to( window->surface, tier->region->surface, &src, tmp.x, tmp.y, false ); + + dfb_region_from_rectangle( ®, &tmp ); + + /* Update cursor? */ + cursor_visible = tier->cursor_region; + if (tier->cursor_drawn && dfb_region_region_intersect( &cursor_visible, ® )) { + DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &cursor_visible ); + CoreLayer *layer = dfb_layer_at( tier->layer_id ); + CardState *state = &layer->state; + int x; + int y; + DFBDimension size; + + if (tier->single_mode) { + size.w = tier->single_width; + size.h = tier->single_height; + } + else { + size = tier->size; + } + + x = (s64) stack->cursor.x * (s64) size.w / (s64) sawman_config->resolution.w; + y = (s64) stack->cursor.y * (s64) size.h / (s64) sawman_config->resolution.h; + + D_ASSUME( tier->cursor_bs_valid ); + + D_DEBUG_AT( SaWMan_Cursor, " -> saving background under cursor (%d,%d-%dx%d)\n", + DFB_RECTANGLE_VALS(&rect) ); + + dfb_gfx_copy_to( tier->region->surface, tier->cursor_bs, &rect, + rect.x - tier->cursor_region.x1, + rect.y - tier->cursor_region.y1, true ); + + + /* Set destination. */ + state->destination = tier->region->surface; + state->modified |= SMF_DESTINATION; + + /* Set clipping region. */ + dfb_state_set_clip( state, &cursor_visible ); + + D_DEBUG_AT( SaWMan_Cursor, " -> drawing cursor (%d,%d-%dx%d) at %d,%d\n", + DFB_RECTANGLE_VALS_FROM_REGION(&cursor_visible), x, y ); + + /* draw cursor */ + sawman_draw_cursor( stack, state, &tier->cursor_region, x, y ); + + /* Reset destination. */ + state->destination = NULL; + state->modified |= SMF_DESTINATION; + } + + dfb_layer_region_flip_update( tier->region, ®, flags ); + } + } + } + else { + sawman_update_window( sawman, sawwin, + sawwin->parent ? NULL : region, /* FIXME? */ + flags, SWMUF_SCALE_REGION ); + + if (flags & DSFLIP_ONCE) { + D_DEBUG_AT( SaWMan_FlipOnce, " -> flip once for window id %u\n", window->id ); + tier->update_once = true; + } + + sawman_process_updates( sawman, flags ); + + if (flags & DSFLIP_ONCE) { + while (tier->updates.num_regions) { + D_DEBUG_AT( SaWMan_FlipOnce, " -> waiting for updates...\n" ); + switch (fusion_skirmish_wait( &sawman->lock, + sawman_config->flip_once_timeout ? + sawman_config->flip_once_timeout + 10 : 0 )) + { + case DR_TIMEOUT: + D_DEBUG_AT( SaWMan_FlipOnce, " -> timeout waiting for updates!\n" ); + + sawman_process_updates( sawman, flags ); + break; + + default: + break; + } + } + + D_DEBUG_AT( SaWMan_FlipOnce, " -> updates done.\n" ); + } + } + + /* Unlock SaWMan. */ + sawman_unlock( sawman ); + + return DFB_OK; +} + +static DFBResult +update_hw_cursor( SaWMan *sawman, + CoreWindowStack *stack, + CoreCursorUpdateFlags flags ) +{ + DFBResult ret; + int x, y; + int mx, my; + CoreLayer *layer; + CoreLayerRegionConfig config; + CoreLayerRegionConfigFlags config_flags = CLRCF_NONE; + + D_DEBUG_AT( SaWMan_Cursor, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, sawman, stack, flags ); + + D_MAGIC_ASSERT( sawman, SaWMan ); + D_ASSERT( stack != NULL ); + + layer = dfb_layer_at( stack->context->layer_id ); + + dfb_screen_get_layer_dimension( layer->screen, layer, &mx, &my ); + + x = (s64) stack->cursor.x * (s64) mx / (s64) sawman_config->resolution.w; + y = (s64) stack->cursor.y * (s64) my / (s64) sawman_config->resolution.h; + + D_DEBUG_AT( SaWMan_Cursor, " -> position %4d,%4d (%d,%d)\n", x, y, stack->cursor.x, stack->cursor.y ); + + // FIXME: initial update flags from DirectFB are CCUF_ENABLE only! + if (!sawman->cursor.region->surface) { + flags |= CCUF_POSITION | CCUF_SIZE | CCUF_SHAPE; + + config_flags = CLRCF_ALL; + config = sawman->cursor.context->primary.config; + } + + if (flags & CCUF_OPACITY) { + if (stack->cursor.opacity) { + if (!(sawman->cursor.region->state & CLRSF_ENABLED)) { + D_DEBUG_AT( SaWMan_Cursor, " -> OPACITY %d, enabling region\n", stack->cursor.opacity ); + + flags |= CCUF_ENABLE; + } + } + else { + if (sawman->cursor.region->state & CLRSF_ENABLED) { + D_DEBUG_AT( SaWMan_Cursor, " -> OPACITY %d, disabling region\n", stack->cursor.opacity ); + + flags |= CCUF_DISABLE; + } + } + } + + if (flags & CCUF_DISABLE) { + D_DEBUG_AT( SaWMan_Cursor, " -> DISABLE\n" ); + + dfb_layer_region_disable( sawman->cursor.region ); + } + + if (flags & (CCUF_POSITION | CCUF_SIZE | CCUF_SHAPE | CLRCF_SOURCE)) { + DFBRegion clip = { 0, 0, mx-1, my-1 }; + + if (flags & CCUF_POSITION) + D_DEBUG_AT( SaWMan_Cursor, " -> POSITION %4d,%4d (hot %d,%d)\n", + x, y, stack->cursor.hot.x, stack->cursor.hot.y ); + + if (flags & CCUF_SIZE) + D_DEBUG_AT( SaWMan_Cursor, " -> SIZE %4dx%4d\n", + stack->cursor.size.w, stack->cursor.size.h ); + + config_flags |= CLRCF_DEST | CLRCF_SOURCE; + + config.dest.x = x - stack->cursor.hot.x; + config.dest.y = y - stack->cursor.hot.y; + config.dest.w = stack->cursor.size.w; + config.dest.h = stack->cursor.size.h; + + config.source.x = 0; + config.source.y = 0; + config.source.w = stack->cursor.surface->config.size.w; + config.source.h = stack->cursor.surface->config.size.h; + + if (!dfb_clip_blit_precheck( &clip, config.dest.w, config.dest.h, config.dest.x, config.dest.y )) { + D_DEBUG_AT( SaWMan_Cursor, " -> PRECHECK against %d,%d-%dx%d failed!\n", DFB_RECTANGLE_VALS_FROM_REGION(&clip) ); + return DFB_INVAREA; + } + + dfb_clip_blit( &clip, &config.source, &config.dest.x, &config.dest.y ); + + D_DEBUG_AT( SaWMan_Cursor, " -> CLIPPED %4d,%4d-%4dx%4d -> %4d,%4d\n", + DFB_RECTANGLE_VALS( &config.source ), config.dest.x, config.dest.y ); + + config.dest.w = config.source.w; + config.dest.h = config.source.h; + + } + + if (flags & CCUF_OPACITY) { + D_DEBUG_AT( SaWMan_Cursor, " -> OPACITY %d\n", stack->cursor.opacity ); + + config_flags |= CLRCF_OPACITY; + + config.opacity = stack->cursor.opacity; +/* + if (config.opacity) { + dfb_layer_region_enable( sawman->cursor.region ); + } + else + dfb_layer_region_disable( sawman->cursor.region ); +*/ + } + + if (flags & CCUF_SHAPE) { + D_DEBUG_AT( SaWMan_Cursor, " -> SHAPE (%dx%d %s, caps 0x%08x)\n", + stack->cursor.surface->config.size.w, + stack->cursor.surface->config.size.h, + dfb_pixelformat_name( stack->cursor.surface->config.format ), + stack->cursor.surface->config.caps ); + + config_flags |= CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_SURFACE_CAPS | CLRCF_FREEZE | CLRCF_OPTIONS; + + config.width = config.source.w; + config.height = config.source.h; + config.format = stack->cursor.surface->config.format; + config.surface_caps = stack->cursor.surface->config.caps; + config.options = DLOP_OPACITY | + (DFB_PIXELFORMAT_HAS_ALPHA( stack->cursor.surface->config.format ) ? DLOP_ALPHACHANNEL : DLOP_NONE); + } + + if (config_flags) { + D_DEBUG_AT( SaWMan_Cursor, " -> reconfiguring... (flags 0x%08x)\n", config_flags ); + + ret = dfb_layer_region_set_configuration( sawman->cursor.region, &config, config_flags ); + if (ret) { + D_DERROR( ret, "SaWMan/Cursor: Failed to reconfigure HW Cursor layer region!\n" ); + return ret; + } + + D_DEBUG_AT( SaWMan_Cursor, " -> reconfiguring done.\n" ); + } + + if (flags & CCUF_SHAPE) { + ret = dfb_layer_region_set_surface( sawman->cursor.region, stack->cursor.surface ); + if (ret) { + D_DERROR( ret, "SaWMan/Cursor: Failed to set HW Cursor layer surface!\n" ); + return ret; + } + } + + if (flags & CCUF_ENABLE) { + D_DEBUG_AT( SaWMan_Cursor, " -> ENABLE\n" ); + + dfb_layer_region_enable( sawman->cursor.region ); + } + + if (flags & (CCUF_SHAPE | CCUF_ENABLE)) { + D_DEBUG_AT( SaWMan_Cursor, " -> updating region...\n" ); + + dfb_layer_region_flip_update( sawman->cursor.region, NULL, DSFLIP_NONE ); + + D_DEBUG_AT( SaWMan_Cursor, " -> updating region done.\n" ); + } + + return DFB_OK; +} + +static DFBResult +wm_update_cursor( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreCursorUpdateFlags flags ) +{ + DFBResult ret; + DFBRegion old_region; + WMData *wmdata = wm_data; + bool restored = false; + CoreLayerContext *context; + CoreLayerRegion *primary; + CoreSurface *surface; + SaWMan *sawman; + SaWManTier *tier; + int x; + int y; + DFBDimension size; + + D_DEBUG_AT( SaWMan_Cursor, "%s( %p, %p, %p, 0x%08x )\n", __FUNCTION__, stack, wm_data, stack_data, flags ); + + D_ASSERT( stack != NULL ); + D_ASSERT( wm_data != NULL ); + D_ASSERT( stack_data != NULL ); + + sawman = wmdata->sawman; + D_MAGIC_ASSERT( sawman, SaWMan ); + + /* Lock SaWMan. */ + ret = sawman_lock( sawman ); + if (ret) + return ret; + + /* Retrieve corresponding SaWManTier. */ + if (!sawman_tier_by_stack( sawman, stack, &tier )) { + sawman_unlock( sawman ); + return DFB_UNSUPPORTED; + } + + if (tier->single_mode) { + size.w = tier->single_width; + size.h = tier->single_height; + } + else { + size = tier->size; + } + + x = (s64) stack->cursor.x * (s64) size.w / (s64) sawman_config->resolution.w; + y = (s64) stack->cursor.y * (s64) size.h / (s64) sawman_config->resolution.h; + + D_DEBUG_AT( SaWMan_Cursor, " -> position %4d,%4d (%d,%d)\n", x, y, stack->cursor.x, stack->cursor.y ); + + old_region = tier->cursor_region; + + if (flags & (CCUF_ENABLE | CCUF_POSITION | CCUF_SIZE)) { + tier->cursor_region.x1 = x - stack->cursor.hot.x; + tier->cursor_region.y1 = y - stack->cursor.hot.y; + tier->cursor_region.x2 = tier->cursor_region.x1 + stack->cursor.size.w - 1; + tier->cursor_region.y2 = tier->cursor_region.y1 + stack->cursor.size.h - 1; + + if (!dfb_region_intersect( &tier->cursor_region, 0, 0, size.w - 1, size.h - 1 )) { + tier->cursor_region.x1 = 1; + tier->cursor_region.x2 = 0; + } + + tier->cursor_bs_valid = false; + } + + /* + * HW Cursor mode? + */ + if (sawman->cursor.region) { + ret = update_hw_cursor( sawman, stack, flags ); + + sawman_unlock( sawman ); + + return ret; + } + + /* Optimize case of invisible cursor moving. */ + if (!(flags & ~(CCUF_POSITION | CCUF_SHAPE)) && (!stack->cursor.opacity || !stack->cursor.enabled)) { + sawman_unlock( sawman ); + return DFB_OK; + } + + /* + * SW Cursor mode + */ + context = stack->context; + D_ASSERT( context != NULL ); + + if (!tier->cursor_bs) { + CoreSurface *cursor_bs; + + D_ASSUME( flags & CCUF_ENABLE ); + + /* Create the cursor backing store surface. */ + ret = dfb_surface_create_simple( wmdata->core, stack->cursor.size.w, stack->cursor.size.h, + context->config.pixelformat, DSCAPS_NONE, + CSTF_SHARED | CSTF_CURSOR, 0, NULL, &cursor_bs ); + if (ret) { + D_ERROR( "WM/Default: Failed creating backing store for cursor!\n" ); + sawman_unlock( sawman ); + return ret; + } + + ret = dfb_surface_globalize( cursor_bs ); + D_ASSERT( ret == DFB_OK ); + + tier->cursor_bs = cursor_bs; + } + + D_ASSERT( tier->cursor_bs != NULL ); + + /* Get the primary region. */ + primary = tier->region; + D_ASSERT( primary != NULL ); + + surface = primary->surface; + D_ASSERT( surface != NULL ); + + if (flags & CCUF_ENABLE) { + /* Ensure valid back buffer. From now on swapping is prevented until cursor is disabled. + * FIXME: Keep a flag to know when back/front have been swapped and need a sync. + */ + switch (context->config.buffermode) { + case DLBM_BACKVIDEO: + case DLBM_TRIPLE: + dfb_gfx_copy( surface, surface, NULL ); + break; + + default: + break; + } + } + + /* restore region under cursor */ + if (tier->cursor_drawn) { + DFBRectangle rect = { 0, 0, + old_region.x2 - old_region.x1 + 1, + old_region.y2 - old_region.y1 + 1 }; + + D_ASSERT( stack->cursor.opacity || (flags & CCUF_OPACITY) ); + + if (tier->active) { + dfb_gfx_copy_to( tier->cursor_bs, surface, &rect, old_region.x1, old_region.y1, false ); + + restored = true; + } + + tier->cursor_drawn = false; + } + + if (flags & CCUF_SIZE) { + ret = dfb_surface_reformat( tier->cursor_bs, + stack->cursor.size.w, stack->cursor.size.h, + tier->cursor_bs->config.format ); + if (ret) + D_DERROR( ret, "WM/Default: Failed resizing backing store for cursor from %dx%d to %dx%d!\n", + tier->cursor_bs->config.size.w, tier->cursor_bs->config.size.h, stack->cursor.size.w, stack->cursor.size.h ); + } + + if (flags & CCUF_DISABLE) { + dfb_surface_unlink( &tier->cursor_bs ); + } +// else if (stack->cursor.opacity && tier->active && tier->cursor_region.x1 <= tier->cursor_region.x2) { + else if (0) { // To be Fix JMH JJJJJJJJJJJJJJJJJJJJJJJJJJJJ + CoreLayer *layer = dfb_layer_at( context->layer_id ); + CardState *state = &layer->state; + + /* backup region under cursor */ + if (!tier->cursor_bs_valid) { + DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &tier->cursor_region ); + + D_ASSERT( !tier->cursor_drawn ); + + /* FIXME: this requires using blitted flipping all the time, + but fixing it seems impossible, for now DSFLIP_BLIT is forced + in repaint_stack() when the cursor is enabled. */ + dfb_gfx_copy_to( surface, tier->cursor_bs, &rect, 0, 0, true ); + + tier->cursor_bs_valid = true; + } + + /* Set destination. */ + state->destination = surface; + state->modified |= SMF_DESTINATION; + + /* Set clipping region. */ + dfb_state_set_clip( state, &tier->cursor_region ); + + /* draw cursor */ + sawman_draw_cursor( stack, state, &tier->cursor_region, x, y ); + + /* Reset destination. */ + state->destination = NULL; + state->modified |= SMF_DESTINATION; + + tier->cursor_drawn = true; + + if (restored) { + if (dfb_region_region_intersects( &old_region, &tier->cursor_region )) + dfb_region_region_union( &old_region, &tier->cursor_region ); + else + dfb_layer_region_flip_update( primary, &tier->cursor_region, DSFLIP_BLIT ); + + dfb_layer_region_flip_update( primary, &old_region, DSFLIP_BLIT ); + } + else + dfb_layer_region_flip_update( primary, &tier->cursor_region, DSFLIP_BLIT ); + } + else if (restored) + dfb_layer_region_flip_update( primary, &old_region, DSFLIP_BLIT ); + + sawman_unlock( sawman ); + + return DFB_OK; +} + -- cgit