summaryrefslogtreecommitdiff
path: root/Source/DirectFB/src/core/layer_context.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/src/core/layer_context.c')
-rwxr-xr-xSource/DirectFB/src/core/layer_context.c1947
1 files changed, 1947 insertions, 0 deletions
diff --git a/Source/DirectFB/src/core/layer_context.c b/Source/DirectFB/src/core/layer_context.c
new file mode 100755
index 0000000..1dcccc8
--- /dev/null
+++ b/Source/DirectFB/src/core/layer_context.c
@@ -0,0 +1,1947 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ 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 <config.h>
+
+#include <unistd.h>
+#include <string.h>
+
+#include <directfb.h>
+
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/shmalloc.h>
+
+#include <core/coredefs.h>
+#include <core/coretypes.h>
+
+#include <core/core.h>
+#include <core/layer_context.h>
+#include <core/layer_control.h>
+#include <core/layer_region.h>
+#include <core/screen.h>
+#include <core/surface.h>
+#include <core/system.h>
+#include <core/windows.h>
+#include <core/windowstack.h>
+#include <core/wm.h>
+
+#include <core/layers_internal.h>
+#include <core/windows_internal.h>
+
+#include <fusion/shmalloc.h>
+
+
+D_DEBUG_DOMAIN( Core_LayerContext, "Core/LayerContext", "DirectFB Display Layer Context" );
+
+/**********************************************************************************************************************/
+
+static void init_region_config ( CoreLayerContext *context,
+ CoreLayerRegionConfig *config );
+
+static void build_updated_config( CoreLayer *layer,
+ CoreLayerContext *context,
+ const DFBDisplayLayerConfig *update,
+ CoreLayerRegionConfig *ret_config,
+ CoreLayerRegionConfigFlags *ret_flags );
+
+static DFBResult allocate_surface ( CoreLayer *layer,
+ CoreLayerRegion *region,
+ CoreLayerRegionConfig *config );
+
+static DFBResult reallocate_surface ( CoreLayer *layer,
+ CoreLayerRegion *region,
+ CoreLayerRegionConfig *config );
+
+static DFBResult deallocate_surface ( CoreLayer *layer,
+ CoreLayerRegion *region );
+
+static void screen_rectangle ( CoreLayerContext *context,
+ const DFBLocation *location,
+ DFBRectangle *rect );
+
+/**********************************************************************************************************************/
+
+static void
+context_destructor( FusionObject *object, bool zombie, void *ctx )
+{
+ CoreLayerContext *context = (CoreLayerContext*) object;
+ CoreLayer *layer = dfb_layer_at( context->layer_id );
+ CoreLayerShared *shared = layer->shared;
+
+ (void) shared;
+
+ D_DEBUG_AT( Core_LayerContext, "*~ destroying context %p (%s, %sactive%s)\n",
+ context, shared->description.name, context->active ? "" : "in",
+ zombie ? " - ZOMBIE" : "");
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Remove the context from the layer's context stack. */
+ dfb_layer_remove_context( layer, context );
+
+ /*
+ * Detach input devices before taking the context lock to prevent a
+ * deadlock between windowstack destruction and input event processing.
+ */
+ if (context->stack)
+ dfb_windowstack_detach_devices( context->stack );
+
+ dfb_layer_context_lock( context );
+
+ /* Destroy the window stack. */
+ if (context->stack) {
+ dfb_windowstack_destroy( context->stack );
+ context->stack = NULL;
+ }
+
+ /* Destroy the region vector. */
+ fusion_vector_destroy( &context->regions );
+
+ /* Deinitialize the lock. */
+ fusion_skirmish_destroy( &context->lock );
+
+ /* Free clip regions. */
+ if (context->primary.config.clips)
+ SHFREE( context->shmpool, context->primary.config.clips );
+
+ D_MAGIC_CLEAR( context );
+
+ /* Destroy the object. */
+ fusion_object_destroy( object );
+}
+
+/**********************************************************************************************************************/
+
+FusionObjectPool *
+dfb_layer_context_pool_create( const FusionWorld *world )
+{
+ return fusion_object_pool_create( "Layer Context Pool",
+ sizeof(CoreLayerContext),
+ sizeof(CoreLayerContextNotification),
+ context_destructor, NULL, world );
+}
+
+/**********************************************************************************************************************/
+
+static void
+update_stack_geometry( CoreLayerContext *context )
+{
+ DFBDimension size;
+ int rotation;
+ CoreLayerRegion *region;
+ CoreSurface *surface;
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ rotation = context->rotation;
+
+ switch (rotation) {
+ default:
+ D_BUG( "invalid rotation %d", rotation );
+ case 0:
+ case 180:
+ size.w = context->config.width;
+ size.h = context->config.height;
+ break;
+
+ case 90:
+ case 270:
+ size.w = context->config.height;
+ size.h = context->config.width;
+ break;
+ }
+
+ region = context->primary.region;
+ if (region) {
+ surface = region->surface;
+ if (surface) {
+ D_MAGIC_ASSERT( surface, CoreSurface );
+
+ rotation -= surface->rotation;
+ if (rotation < 0)
+ rotation += 360;
+ }
+ }
+
+ dfb_windowstack_resize( context->stack, size.w, size.h, rotation );
+}
+
+DFBResult
+dfb_layer_context_init( CoreLayerContext *context,
+ CoreLayer *layer )
+{
+ CoreLayerShared *shared;
+
+ D_ASSERT( context != NULL );
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->shared != NULL );
+
+ shared = layer->shared;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p [%s] )\n", __FUNCTION__, context, layer, shared->description.name );
+
+ context->shmpool = shared->shmpool;
+
+ /* Initialize the lock. */
+ if (fusion_skirmish_init( &context->lock, "Layer Context", dfb_core_world(layer->core) )) {
+ fusion_object_destroy( &context->object );
+ return DFB_FUSION;
+ }
+
+ /* Initialize the region vector. */
+ fusion_vector_init( &context->regions, 4, context->shmpool );
+
+ /* Store layer ID, default configuration and default color adjustment. */
+ context->layer_id = shared->layer_id;
+ context->config = shared->default_config;
+ context->adjustment = shared->default_adjustment;
+ context->rotation = dfb_config->layers[dfb_layer_id_translated(layer)].rotate;
+
+ /* Initialize screen location. */
+ context->screen.location.x = 0.0f;
+ context->screen.location.y = 0.0f;
+ context->screen.location.w = 1.0f;
+ context->screen.location.h = 1.0f;
+
+ if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_LOCATION ))
+ context->screen.mode = CLLM_LOCATION;
+ else if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_POSITION ))
+ context->screen.mode = CLLM_CENTER;
+
+ /* Change global reaction lock. */
+ fusion_object_set_lock( &context->object, &context->lock );
+
+ D_MAGIC_SET( context, CoreLayerContext );
+
+ /* Initialize the primary region's configuration. */
+ init_region_config( context, &context->primary.config );
+
+ /* Activate the object. */
+ fusion_object_activate( &context->object );
+
+
+ dfb_layer_context_lock( context );
+
+ /* Create the window stack. */
+ context->stack = dfb_windowstack_create( context );
+ if (!context->stack) {
+ dfb_layer_context_unlock( context );
+ dfb_layer_context_unref( context );
+ return D_OOSHM();
+ }
+
+ /* Tell the window stack about its size. */
+ update_stack_geometry( context );
+
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_activate( CoreLayerContext *context )
+{
+ DFBResult ret;
+ int index;
+ CoreLayer *layer;
+ CoreLayerRegion *region;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->funcs != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ D_ASSUME( !context->active );
+
+ if (context->active) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Iterate through all regions. */
+ fusion_vector_foreach (region, index, context->regions) {
+ /* Activate each region. */
+ if (dfb_layer_region_activate( region ))
+ D_WARN( "could not activate region!" );
+
+ if (region->surface && region->surface->num_buffers == 0) {
+ D_ASSERT( region->surface_lock.buffer == NULL );
+
+ ret = reallocate_surface( layer, region, &region->config );
+ if (ret)
+ D_DERROR( ret, "Core/Layers: Reallocation of layer surface failed!\n" );
+ }
+ }
+
+ context->active = true;
+
+ /* set new adjustment */
+ if (layer->funcs->SetColorAdjustment)
+ layer->funcs->SetColorAdjustment( layer, layer->driver_data,
+ layer->layer_data, &context->adjustment );
+
+ /* Resume window stack. */
+ if (context->stack) {
+ CoreWindowStack *stack = context->stack;
+
+ D_MAGIC_ASSERT( stack, CoreWindowStack );
+
+ if (stack->flags & CWSF_INITIALIZED)
+ dfb_wm_set_active( stack, true );
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_deactivate( CoreLayerContext *context )
+{
+ int index;
+ CoreLayerRegion *region;
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context );
+
+ D_ASSUME( context->active );
+
+ if (!context->active) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Iterate through all regions. */
+ fusion_vector_foreach (region, index, context->regions) {
+ /* Deactivate each region. */
+ dfb_layer_region_deactivate( region );
+ }
+
+ context->active = false;
+
+ /* Suspend window stack. */
+ if (context->stack) {
+ CoreWindowStack *stack = context->stack;
+
+ D_MAGIC_ASSERT( stack, CoreWindowStack );
+
+ if (stack->flags & CWSF_ACTIVATED)
+ dfb_wm_set_active( stack, false );
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_add_region( CoreLayerContext *context,
+ CoreLayerRegion *region )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, region );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( region != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ D_ASSUME( ! fusion_vector_contains( &context->regions, region ) );
+
+ if (fusion_vector_contains( &context->regions, region )) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Add region to vector. */
+ if (fusion_vector_add( &context->regions, region )) {
+ dfb_layer_context_unlock( context );
+ return DFB_FUSION;
+ }
+
+ /* Inherit state from context. */
+ if (context->active)
+ region->state |= CLRSF_ACTIVE;
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_remove_region( CoreLayerContext *context,
+ CoreLayerRegion *region )
+{
+ int index;
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( region != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ D_ASSUME( fusion_vector_contains( &context->regions, region ) );
+
+ /* Lookup region. */
+ index = fusion_vector_index_of( &context->regions, region );
+ if (index < 0) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Remove region from vector. */
+ fusion_vector_remove( &context->regions, index );
+
+ /* Check if the primary region is removed. */
+ if (region == context->primary.region)
+ context->primary.region = NULL;
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_get_primary_region( CoreLayerContext *context,
+ bool create,
+ CoreLayerRegion **ret_region )
+{
+ DFBResult ret = DFB_OK;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %screate )\n", __FUNCTION__, context, create ? "" : "DON'T " );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( ret_region != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+restart:
+ while (context->primary.region) {
+ /* Increase the primary region's reference counter. */
+ ret = dfb_layer_region_ref( context->primary.region );
+ if (ret == DFB_OK)
+ break;
+
+ dfb_layer_context_unlock( context );
+
+ if (ret == DFB_LOCKED) {
+ //sched_yield();
+ usleep( 10000 );
+
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+ }
+ else
+ return DFB_FUSION;
+ }
+
+ if (!context->primary.region) {
+ if (create) {
+ CoreLayerRegion *region;
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ /* Create the primary region. */
+ ret = dfb_layer_region_create( context, &region );
+ if (ret) {
+ D_ERROR( "DirectFB/core/layers: Could not create primary region!\n" );
+ return ret;
+ }
+
+ /* Lock the context again. */
+ if (dfb_layer_context_lock( context )) {
+ dfb_layer_region_unref( region );
+ return DFB_FUSION;
+ }
+
+ /* Check for race. */
+ if (context->primary.region) {
+ dfb_layer_region_unref( region );
+ goto restart;
+ }
+
+ /* Set the region configuration. */
+ ret = dfb_layer_region_set_configuration( region,
+ &context->primary.config,
+ CLRCF_ALL );
+ if (ret) {
+ D_DERROR( ret, "DirectFB/core/layers: "
+ "Could not set primary region config!\n" );
+ dfb_layer_region_unref( region );
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+
+ /* Remember the primary region. */
+ context->primary.region = region;
+
+ /* Allocate surface, enable region etc. */
+ ret = dfb_layer_context_set_configuration( context, &context->config );
+ if (ret) {
+ D_DERROR( ret, "DirectFB/core/layers: "
+ "Could not set layer context config!\n" );
+ context->primary.region = NULL;
+ dfb_layer_region_unref( region );
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+ }
+ else {
+ dfb_layer_context_unlock( context );
+ return DFB_TEMPUNAVAIL;
+ }
+ }
+
+ /* Return region. */
+ *ret_region = context->primary.region;
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+/*
+ * configuration management
+ */
+DFBResult
+dfb_layer_context_test_configuration( CoreLayerContext *context,
+ const DFBDisplayLayerConfig *config,
+ DFBDisplayLayerConfigFlags *ret_failed )
+{
+ DFBResult ret = DFB_OK;
+ CoreLayer *layer;
+ CoreLayerRegionConfig region_config;
+ CoreLayerRegionConfigFlags failed;
+ const DisplayLayerFuncs *funcs;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, config, ret_failed );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( config != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->shared != NULL );
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( layer->funcs->TestRegion != NULL );
+
+ funcs = layer->funcs;
+
+ /* Build a new region configuration with the changes. */
+ build_updated_config( layer, context, config, &region_config, NULL );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+
+ /* Test the region configuration. */
+ if (region_config.buffermode == DLBM_WINDOWS) {
+ if (! D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_WINDOWS )) {
+ failed = CLRCF_BUFFERMODE;
+ ret = DFB_UNSUPPORTED;
+ }
+ }
+ else {
+ /* Let the driver examine the modified configuration. */
+ ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data,
+ &region_config, &failed );
+ }
+
+ /* Return flags for failing entries. */
+ if (ret_failed) {
+ DFBDisplayLayerConfigFlags flags = DLCONF_NONE;
+
+ /* Translate flags. */
+ if (ret != DFB_OK) {
+ if (failed & CLRCF_WIDTH)
+ flags |= DLCONF_WIDTH;
+
+ if (failed & CLRCF_HEIGHT)
+ flags |= DLCONF_HEIGHT;
+
+ if (failed & CLRCF_FORMAT)
+ flags |= DLCONF_PIXELFORMAT;
+
+ if (failed & CLRCF_BUFFERMODE)
+ flags |= DLCONF_BUFFERMODE;
+
+ if (failed & CLRCF_OPTIONS)
+ flags |= DLCONF_OPTIONS;
+
+ if (failed & CLRCF_SOURCE_ID)
+ flags |= DLCONF_SOURCE;
+
+ if (failed & CLRCF_SURFACE_CAPS)
+ flags |= DLCONF_SURFACE_CAPS;
+ }
+
+ *ret_failed = flags;
+ }
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_configuration( CoreLayerContext *context,
+ const DFBDisplayLayerConfig *config )
+{
+ int i;
+ DFBResult ret;
+ CoreLayer *layer;
+ CoreLayerShared *shared;
+ CoreLayerRegionConfig region_config;
+ CoreLayerRegionConfigFlags flags;
+ const DisplayLayerFuncs *funcs;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( config != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->shared != NULL );
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( layer->funcs->TestRegion != NULL );
+
+ shared = layer->shared;
+ funcs = layer->funcs;
+
+ /* Build a new region configuration with the changes. */
+ build_updated_config( layer, context, config, &region_config, &flags );
+
+ /* Test the region configuration first. */
+ if (region_config.buffermode == DLBM_WINDOWS) {
+ if (! D_FLAGS_IS_SET( shared->description.caps, DLCAPS_WINDOWS )) {
+ dfb_layer_context_unlock( context );
+ return DFB_UNSUPPORTED;
+ }
+ }
+ else {
+ ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data,
+ &region_config, NULL );
+ if (ret) {
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+ }
+
+ /* Set the region configuration. */
+ if (context->primary.region) {
+ CoreLayerRegion *region = context->primary.region;
+
+ /* Add local reference. */
+ if (dfb_layer_region_ref( region )) {
+ dfb_layer_context_unlock( context );
+ return DFB_FUSION;
+ }
+
+ /* Lock the region. */
+ if (dfb_layer_region_lock( region )) {
+ dfb_layer_region_unref( region );
+ dfb_layer_context_unlock( context );
+ return DFB_FUSION;
+ }
+
+ /* Normal buffer mode? */
+ if (region_config.buffermode != DLBM_WINDOWS) {
+ bool surface = shared->description.caps & DLCAPS_SURFACE;
+ CoreLayerRegionStateFlags configured = region->state & CLRSF_CONFIGURED;
+
+ if (shared->description.caps & DLCAPS_SOURCES) {
+ for (i=0; i<shared->description.sources; i++) {
+ if (shared->sources[i].description.source_id == region_config.source_id)
+ break;
+ }
+
+ D_ASSERT( i < shared->description.sources );
+
+ surface = shared->sources[i].description.caps & DDLSCAPS_SURFACE;
+ }
+
+ D_FLAGS_CLEAR( region->state, CLRSF_CONFIGURED );
+
+ /* Unlock the region surface */
+ if (region->surface) {
+ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) {
+ if (!D_FLAGS_IS_SET( region->state, CLRSF_FROZEN ))
+ D_ASSUME( region->surface_lock.buffer != NULL );
+
+ if (region->surface_lock.buffer)
+ dfb_surface_unlock_buffer( region->surface, &region->surface_lock );
+ }
+ }
+
+ /* (Re)allocate the region's surface. */
+ if (surface) {
+ flags |= CLRCF_SURFACE | CLRCF_PALETTE;
+
+ if (region->surface) {
+ ret = reallocate_surface( layer, region, &region_config );
+ if (ret)
+ D_DERROR( ret, "Core/Layers: Reallocation of layer surface failed!\n" );
+ }
+ else {
+ ret = allocate_surface( layer, region, &region_config );
+ if (ret)
+ D_DERROR( ret, "Core/Layers: Allocation of layer surface failed!\n" );
+ }
+
+ if (ret) {
+ dfb_layer_region_unlock( region );
+ dfb_layer_region_unref( region );
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+ }
+ else if (region->surface)
+ deallocate_surface( layer, region );
+
+ region->state |= configured;
+
+ /* Set the new region configuration. */
+ dfb_layer_region_set_configuration( region, &region_config, flags );
+
+ /* Enable the primary region. */
+ if (! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ))
+ dfb_layer_region_enable( region );
+ }
+ else {
+ /* Disable and deallocate the primary region. */
+ if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) {
+ dfb_layer_region_disable( region );
+
+ if (region->surface)
+ deallocate_surface( layer, region );
+ }
+ }
+
+ /* Unlock the region and give up the local reference. */
+ dfb_layer_region_unlock( region );
+ dfb_layer_region_unref( region );
+ }
+
+ /* Remember new region config. */
+ context->primary.config = region_config;
+
+ /*
+ * Write back modified entries.
+ */
+ if (config->flags & DLCONF_WIDTH)
+ context->config.width = config->width;
+
+ if (config->flags & DLCONF_HEIGHT)
+ context->config.height = config->height;
+
+ if (config->flags & DLCONF_PIXELFORMAT)
+ context->config.pixelformat = config->pixelformat;
+
+ if (config->flags & DLCONF_BUFFERMODE)
+ context->config.buffermode = config->buffermode;
+
+ if (config->flags & DLCONF_OPTIONS)
+ context->config.options = config->options;
+
+ if (config->flags & DLCONF_SOURCE)
+ context->config.source = config->source;
+
+ if (config->flags & DLCONF_SURFACE_CAPS)
+ context->config.surface_caps = config->surface_caps;
+
+ /* Update the window stack. */
+ if (context->stack) {
+ CoreWindowStack *stack = context->stack;
+
+ /* Update hardware flag. */
+ stack->hw_mode = (region_config.buffermode == DLBM_WINDOWS);
+
+ /* Tell the windowing core about the new size. */
+ if (config->flags & (DLCONF_WIDTH | DLCONF_HEIGHT |
+ DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_SURFACE_CAPS))
+ {
+ update_stack_geometry( context );
+
+ /* FIXME: call only if really needed */
+ dfb_windowstack_repaint_all( stack );
+ }
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_get_configuration( CoreLayerContext *context,
+ DFBDisplayLayerConfig *config )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( config != NULL );
+
+ *config = context->config;
+
+ return DFB_OK;
+}
+
+static DFBResult
+update_primary_region_config( CoreLayerContext *context,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags flags )
+{
+ DFBResult ret = DFB_OK;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, context, config, flags );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( config != NULL );
+
+ if (context->primary.region) {
+ /* Set the new configuration. */
+ ret = dfb_layer_region_set_configuration( context->primary.region, config, flags );
+ }
+ else {
+ CoreLayer *layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( layer->funcs->TestRegion != NULL );
+
+ /* Just test the new configuration. */
+ ret = layer->funcs->TestRegion( layer, layer->driver_data,
+ layer->layer_data, config, NULL );
+ }
+
+ if (ret)
+ return ret;
+
+ /* Remember the configuration. */
+ context->primary.config = *config;
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_set_src_colorkey( CoreLayerContext *context,
+ u8 r, u8 g, u8 b, int index )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Change the color key. */
+ config.src_key.r = r;
+ config.src_key.g = g;
+ config.src_key.b = b;
+
+ if (index >= 0)
+ config.src_key.index = index & 0xff;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_SRCKEY );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_dst_colorkey( CoreLayerContext *context,
+ u8 r, u8 g, u8 b, int index )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Change the color key. */
+ config.dst_key.r = r;
+ config.dst_key.g = g;
+ config.dst_key.b = b;
+
+ if (index >= 0)
+ config.dst_key.index = index & 0xff;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_DSTKEY );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_sourcerectangle( CoreLayerContext *context,
+ const DFBRectangle *source )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+ CoreLayerRegionConfigFlags flags;
+ CoreLayer *layer;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, source );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( source != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Do nothing if the source rectangle didn't change. */
+ if (DFB_RECTANGLE_EQUAL( config.source, *source )) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Check if the new source rectangle is valid. */
+ if (source->x < 0 || source->y < 0 ||
+ source->x + source->w > config.width ||
+ source->y + source->h > config.height) {
+ dfb_layer_context_unlock( context );
+ return DFB_INVAREA;
+ }
+
+ /* Change the source rectangle. */
+ config.source = *source;
+
+ flags = CLRCF_SOURCE;
+ layer = dfb_layer_at( context->layer_id );
+
+ /* If the display layer does not support scaling and the destination
+ rectangle size is not the same as the source, change it to match. The
+ origin is left alone to allow the driver to handle it. */
+ if ( !D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_SCREEN_SIZE ) &&
+ ( config.dest.w != config.source.w ||
+ config.dest.h != config.source.h ) )
+ {
+ config.dest.w = config.source.w;
+ config.dest.h = config.source.h;
+
+ flags |= CLRCF_DEST;
+ }
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, flags );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_screenlocation( CoreLayerContext *context,
+ const DFBLocation *location )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, location );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( location != NULL );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the location didn't change. */
+/* if (context->screen.mode == CLLM_LOCATION &&
+ DFB_LOCATION_EQUAL( context->screen.location, *location ))
+ {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }*/
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Calculate new absolute screen coordinates. */
+ screen_rectangle( context, location, &config.dest );
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_DEST );
+ if (ret == DFB_OK) {
+ context->screen.location = *location;
+ context->screen.rectangle = config.dest;
+ context->screen.mode = CLLM_LOCATION;
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_screenrectangle( CoreLayerContext *context,
+ const DFBRectangle *rectangle )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, rectangle );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ DFB_RECTANGLE_ASSERT( rectangle );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the location didn't change. */
+/* if (context->screen.mode == CLLM_RECTANGLE &&
+ DFB_RECTANGLE_EQUAL( context->screen.rectangle, *rectangle ))
+ {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }*/
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Use supplied absolute screen coordinates. */
+ config.dest = *rectangle;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_DEST );
+ if (ret == DFB_OK) {
+ context->screen.rectangle = config.dest;
+ context->screen.mode = CLLM_RECTANGLE;
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_screenposition( CoreLayerContext *context,
+ int x,
+ int y )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %4d,%4d )\n", __FUNCTION__, context, x, y );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the location didn't change. */
+ if (context->primary.config.dest.x == x && context->primary.config.dest.y == y) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Set new absolute screen coordinates. */
+ config.dest.x = x;
+ config.dest.y = y;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_DEST );
+ if (ret == DFB_OK) {
+ context->screen.rectangle = config.dest;
+ context->screen.mode = CLLM_POSITION;
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_opacity( CoreLayerContext *context,
+ u8 opacity )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, opacity );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the opacity didn't change. */
+ if (context->primary.config.opacity == opacity) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Change the opacity. */
+ config.opacity = opacity;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_OPACITY );
+ if (ret == DFB_OK)
+ context->primary.config.opacity = opacity;
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_rotation( CoreLayerContext *context,
+ int rotation )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, rotation );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the rotation didn't change. */
+ if (context->rotation != rotation) {
+ context->rotation = rotation;
+
+ update_stack_geometry( context );
+
+ dfb_windowstack_repaint_all( context->stack );
+ }
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_set_coloradjustment( CoreLayerContext *context,
+ const DFBColorAdjustment *adjustment )
+{
+ DFBResult ret;
+ DFBColorAdjustment adj;
+ CoreLayer *layer;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, adjustment );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( adjustment != NULL );
+
+ layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->funcs != NULL );
+
+ adj = context->adjustment;
+
+ if (!layer->funcs->SetColorAdjustment)
+ return DFB_UNSUPPORTED;
+
+ /* if flags are set that are not in the default adjustment */
+ if (adjustment->flags & ~context->adjustment.flags)
+ return DFB_UNSUPPORTED;
+
+ /* take over changed values */
+ if (adjustment->flags & DCAF_BRIGHTNESS) adj.brightness = adjustment->brightness;
+ if (adjustment->flags & DCAF_CONTRAST) adj.contrast = adjustment->contrast;
+ if (adjustment->flags & DCAF_HUE) adj.hue = adjustment->hue;
+ if (adjustment->flags & DCAF_SATURATION) adj.saturation = adjustment->saturation;
+
+ /* set new adjustment */
+ ret = layer->funcs->SetColorAdjustment( layer, layer->driver_data,
+ layer->layer_data, &adj );
+ if (ret)
+ return ret;
+
+ /* keep new adjustment */
+ context->adjustment = adj;
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_get_coloradjustment( CoreLayerContext *context,
+ DFBColorAdjustment *ret_adjustment )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, ret_adjustment );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( ret_adjustment != NULL );
+
+ *ret_adjustment = context->adjustment;
+
+ return DFB_OK;
+}
+
+DFBResult
+dfb_layer_context_set_field_parity( CoreLayerContext *context,
+ int field )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, field );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ /* Do nothing if the parity didn't change. */
+ if (context->primary.config.parity == field) {
+ dfb_layer_context_unlock( context );
+ return DFB_OK;
+ }
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Change the parity. */
+ config.parity = field;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_PARITY );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_set_clip_regions( CoreLayerContext *context,
+ const DFBRegion *regions,
+ int num_regions,
+ DFBBoolean positive )
+{
+ DFBResult ret;
+ CoreLayerRegionConfig config;
+ DFBRegion *clips;
+ DFBRegion *old_clips;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p [%d], %s )\n", __FUNCTION__,
+ context, regions, num_regions, positive ? "positive" : "negative" );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ clips = SHMALLOC( context->shmpool, sizeof(DFBRegion) * num_regions );
+ if (!clips)
+ return D_OOSHM();
+
+ direct_memcpy( clips, regions, sizeof(DFBRegion) * num_regions );
+
+ /* Lock the context. */
+ if (dfb_layer_context_lock( context )) {
+ SHFREE( context->shmpool, clips );
+ return DFB_FUSION;
+ }
+
+ /* Take the current configuration. */
+ config = context->primary.config;
+
+ /* Remember for freeing later on. */
+ old_clips = config.clips;
+
+ /* Change the clip regions. */
+ config.clips = clips;
+ config.num_clips = num_regions;
+ config.positive = positive;
+
+ /* Try to set the new configuration. */
+ ret = update_primary_region_config( context, &config, CLRCF_CLIPS );
+
+ /* Unlock the context. */
+ dfb_layer_context_unlock( context );
+
+ if (ret)
+ SHFREE( context->shmpool, clips );
+ else if (old_clips)
+ SHFREE( context->shmpool, old_clips );
+
+ return ret;
+}
+
+DFBResult
+dfb_layer_context_create_window( CoreDFB *core,
+ CoreLayerContext *context,
+ const DFBWindowDescription *desc,
+ CoreWindow **ret_window )
+{
+ DFBResult ret;
+ CoreWindow *window;
+ CoreWindowStack *stack;
+ CoreLayer *layer;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p )\n", __FUNCTION__, core, context, desc, ret_window );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( context->stack != NULL );
+ D_ASSERT( desc != NULL );
+ D_ASSERT( ret_window != NULL );
+
+ layer = dfb_layer_at( context->layer_id );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->funcs != NULL );
+
+ if (dfb_layer_context_lock( context ))
+ return DFB_FUSION;
+
+ stack = context->stack;
+
+ if (!stack->cursor.set) {
+ ret = dfb_windowstack_cursor_enable( core, stack, true );
+ if (ret) {
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+ }
+
+ ret = dfb_window_create( stack, desc, &window );
+ if (ret) {
+ dfb_layer_context_unlock( context );
+ return ret;
+ }
+
+ *ret_window = window;
+
+ dfb_layer_context_unlock( context );
+
+ return DFB_OK;
+}
+
+CoreWindow *
+dfb_layer_context_find_window( CoreLayerContext *context, DFBWindowID id )
+{
+ CoreWindowStack *stack;
+ CoreWindow *window;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, id );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( context->stack != NULL );
+
+ stack = context->stack;
+
+ if (dfb_layer_context_lock( context ))
+ return NULL;
+
+ if (dfb_wm_window_lookup( stack, id, &window ) || dfb_window_ref( window ))
+ window = NULL;
+
+ dfb_layer_context_unlock( context );
+
+ return window;
+}
+
+CoreWindowStack *
+dfb_layer_context_windowstack( const CoreLayerContext *context )
+{
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ return context->stack;
+}
+
+bool
+dfb_layer_context_active( const CoreLayerContext *context )
+{
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ return context->active;
+}
+
+DirectResult
+dfb_layer_context_lock( CoreLayerContext *context )
+{
+ DFBResult ret;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ ret = fusion_skirmish_prevail( &context->lock );
+ if (ret == DFB_OK) {
+ int locked;
+
+ ret = fusion_skirmish_lock_count( &context->lock, &locked );
+ if (ret == DFB_OK)
+ D_DEBUG_AT( Core_LayerContext, " -> locked %dx now\n", locked );
+ }
+
+ return ret;
+}
+
+DirectResult
+dfb_layer_context_unlock( CoreLayerContext *context )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ return fusion_skirmish_dismiss( &context->lock );
+}
+
+/**************************************************************************************************/
+
+/*
+ * region config construction
+ */
+static void
+init_region_config( CoreLayerContext *context,
+ CoreLayerRegionConfig *config )
+{
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( config != NULL );
+
+ memset( config, 0, sizeof(CoreLayerRegionConfig) );
+
+ /* Initialize values from layer config. */
+ config->width = context->config.width;
+ config->height = context->config.height;
+ config->format = context->config.pixelformat;
+ config->buffermode = context->config.buffermode;
+ config->options = context->config.options;
+ config->source_id = context->config.source;
+ config->surface_caps = context->config.surface_caps;
+
+ /* Initialize source rectangle. */
+ config->source.x = 0;
+ config->source.y = 0;
+ config->source.w = config->width;
+ config->source.h = config->height;
+
+ /* Initialize screen rectangle. */
+ screen_rectangle( context, &context->screen.location, &config->dest );
+
+ /* Set default opacity. */
+ config->opacity = 0xff;
+
+ /* Set default alpha ramp. */
+ config->alpha_ramp[0] = 0x00;
+ config->alpha_ramp[1] = 0x55;
+ config->alpha_ramp[2] = 0xaa;
+ config->alpha_ramp[3] = 0xff;
+}
+
+static void
+build_updated_config( CoreLayer *layer,
+ CoreLayerContext *context,
+ const DFBDisplayLayerConfig *update,
+ CoreLayerRegionConfig *ret_config,
+ CoreLayerRegionConfigFlags *ret_flags )
+{
+ CoreLayerRegionConfigFlags flags = CLRCF_NONE;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p, %p )\n",
+ __FUNCTION__, layer, context, update, ret_config, ret_flags );
+
+ D_ASSERT( layer != NULL );
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( update != NULL );
+ D_ASSERT( ret_config != NULL );
+
+ /* Get the current region configuration. */
+ *ret_config = context->primary.config;
+
+ /* Change width. */
+ if (update->flags & DLCONF_WIDTH) {
+ flags |= CLRCF_WIDTH;
+ ret_config->width = update->width;
+ }
+
+ /* Change height. */
+ if (update->flags & DLCONF_HEIGHT) {
+ flags |= CLRCF_HEIGHT;
+ ret_config->height = update->height;
+ }
+
+ /* Update source and destination rectangle. */
+ if (update->flags & (DLCONF_WIDTH | DLCONF_HEIGHT)) {
+ int width, height;
+ DFBResult ret;
+
+ flags |= CLRCF_SOURCE | CLRCF_DEST;
+
+ ret_config->source.x = 0;
+ ret_config->source.y = 0;
+ ret_config->source.w = ret_config->width;
+ ret_config->source.h = ret_config->height;
+
+ switch (context->screen.mode) {
+ case CLLM_CENTER:
+ ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height );
+ if( ret == DFB_OK ) {
+ ret_config->dest.x = (width - ret_config->width) / 2;
+ ret_config->dest.y = (height - ret_config->height) / 2;
+ }
+ /* fall through */
+
+ case CLLM_POSITION:
+ ret_config->dest.w = ret_config->width;
+ ret_config->dest.h = ret_config->height;
+ break;
+
+ case CLLM_LOCATION:
+ case CLLM_RECTANGLE:
+ D_ASSERT( layer->shared != NULL );
+
+ /* If the display layer does not support scaling and the
+ destination rectangle size is not the same as the
+ source rectangle, change it to match. The origin is
+ left alone to allow the driver to handle it. */
+ if ( !D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_SCREEN_SIZE )
+ && ( ret_config->dest.w != ret_config->source.w ||
+ ret_config->dest.h != ret_config->source.h ) )
+ {
+ ret_config->dest.w = ret_config->width;
+ ret_config->dest.h = ret_config->height;
+ }
+ break;
+
+ default:
+ D_BREAK( "invalid layout mode" );
+ }
+ }
+
+ /* Change pixel format. */
+ if (update->flags & DLCONF_PIXELFORMAT) {
+ flags |= CLRCF_FORMAT;
+ ret_config->format = update->pixelformat;
+ }
+
+ /* Change buffer mode. */
+ if (update->flags & DLCONF_BUFFERMODE) {
+ flags |= CLRCF_BUFFERMODE;
+ ret_config->buffermode = update->buffermode;
+ }
+
+ /* Change options. */
+ if (update->flags & DLCONF_OPTIONS) {
+ flags |= CLRCF_OPTIONS;
+ ret_config->options = update->options;
+ }
+
+ /* Change source id. */
+ if (update->flags & DLCONF_SOURCE) {
+ flags |= CLRCF_SOURCE_ID;
+ ret_config->source_id = update->source;
+ }
+
+ /* Change surface caps. */
+ if (update->flags & DLCONF_SURFACE_CAPS) {
+ flags |= CLRCF_SURFACE_CAPS;
+ ret_config->surface_caps = update->surface_caps;
+ }
+
+ /* Return translated flags. */
+ if (ret_flags)
+ *ret_flags = flags;
+}
+
+/*
+ * region surface (re/de)allocation
+ */
+static DFBResult
+allocate_surface( CoreLayer *layer,
+ CoreLayerRegion *region,
+ CoreLayerRegionConfig *config )
+{
+ DFBResult ret;
+ const DisplayLayerFuncs *funcs;
+ CoreLayerContext *context;
+ CoreSurface *surface = NULL;
+ DFBSurfaceCapabilities caps = DSCAPS_VIDEOONLY;
+ CoreSurfaceTypeFlags type = CSTF_LAYER;
+ CoreSurfaceConfig scon;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->shared != NULL );
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( region != NULL );
+ D_ASSERT( region->surface == NULL );
+ D_ASSERT( config != NULL );
+ D_ASSERT( config->buffermode != DLBM_WINDOWS );
+
+ context = region->context;
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ funcs = layer->funcs;
+
+ /*
+ * Create a new surface for the region.
+ * Drivers may provide their own surface creation (unusual).
+ */
+ if (funcs->AllocateSurface) {
+ /* Let the driver create the surface. */
+ ret = funcs->AllocateSurface( layer, layer->driver_data,
+ layer->layer_data, region->region_data,
+ config, &surface );
+ if (ret) {
+ D_ERROR( "DirectFB/core/layers: AllocateSurface() failed!\n" );
+ return ret;
+ }
+ }
+ else {
+ CoreLayerShared *shared = layer->shared;
+
+ /* Choose surface capabilities depending on the buffer mode. */
+ switch (config->buffermode) {
+ case DLBM_FRONTONLY:
+ break;
+
+ case DLBM_BACKVIDEO:
+ case DLBM_BACKSYSTEM:
+ caps |= DSCAPS_DOUBLE;
+ break;
+
+ case DLBM_TRIPLE:
+ caps |= DSCAPS_TRIPLE;
+ break;
+
+ default:
+ D_BUG("unknown buffermode");
+ break;
+ }
+
+ if (context->rotation == 90 || context->rotation == 270)
+ caps |= DSCAPS_ROTATED;
+
+ /* FIXME: remove this? */
+ if (config->options & DLOP_DEINTERLACING)
+ caps |= DSCAPS_INTERLACED;
+
+ /* Add available surface capabilities. */
+ caps |= config->surface_caps & (DSCAPS_INTERLACED |
+ DSCAPS_SEPARATED |
+ DSCAPS_PREMULTIPLIED);
+
+ scon.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS;
+ scon.size.w = config->width;
+ scon.size.h = config->height;
+ scon.format = config->format;
+ scon.caps = caps;
+
+ if (shared->contexts.primary == region->context)
+ type |= CSTF_SHARED;
+
+ /* Use the default surface creation. */
+ ret = dfb_surface_create( layer->core, &scon, type, shared->layer_id, NULL, &surface );
+ if (ret) {
+ D_DERROR( ret, "Core/layers: Surface creation failed!\n" );
+ return ret;
+ }
+
+ if (config->buffermode == DLBM_BACKSYSTEM)
+ surface->buffers[1]->policy = CSP_SYSTEMONLY;
+ }
+
+ if (surface->config.caps & DSCAPS_ROTATED)
+ surface->rotation = context->rotation;
+ else
+ surface->rotation = (context->rotation == 180) ? 180 : 0;
+
+ /* Tell the region about its new surface (adds a global reference). */
+ ret = dfb_layer_region_set_surface( region, surface );
+
+ /* Remove local reference of dfb_surface_create(). */
+ dfb_surface_unref( surface );
+
+ return ret;
+}
+
+static DFBResult
+reallocate_surface( CoreLayer *layer,
+ CoreLayerRegion *region,
+ CoreLayerRegionConfig *config )
+{
+ DFBResult ret;
+ const DisplayLayerFuncs *funcs;
+ CoreLayerContext *context;
+ CoreSurface *surface;
+ CoreSurfaceConfig sconfig;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( region != NULL );
+ D_ASSERT( region->surface != NULL );
+ D_ASSERT( config != NULL );
+ D_ASSERT( config->buffermode != DLBM_WINDOWS );
+
+ context = region->context;
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+
+ funcs = layer->funcs;
+ surface = region->surface;
+
+ if (funcs->ReallocateSurface)
+ return funcs->ReallocateSurface( layer, layer->driver_data,
+ layer->layer_data,
+ region->region_data,
+ config, surface );
+
+ sconfig.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS;
+
+ sconfig.caps = surface->config.caps & ~(DSCAPS_FLIPPING | DSCAPS_INTERLACED |
+ DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_ROTATED);
+
+ switch (config->buffermode) {
+ case DLBM_TRIPLE:
+ sconfig.caps |= DSCAPS_TRIPLE;
+ break;
+
+ case DLBM_BACKVIDEO:
+ case DLBM_BACKSYSTEM:
+ sconfig.caps |= DSCAPS_DOUBLE;
+ break;
+
+ case DLBM_FRONTONLY:
+ break;
+
+ default:
+ D_BUG("unknown buffermode");
+ return DFB_BUG;
+ }
+
+ if (context->rotation == 90 || context->rotation == 270)
+ sconfig.caps |= DSCAPS_ROTATED;
+
+ /* Add available surface capabilities. */
+ sconfig.caps |= config->surface_caps & (DSCAPS_INTERLACED |
+ DSCAPS_SEPARATED |
+ DSCAPS_PREMULTIPLIED);
+
+ if (config->options & DLOP_DEINTERLACING)
+ sconfig.caps |= DSCAPS_INTERLACED;
+
+ sconfig.size.w = config->width;
+ sconfig.size.h = config->height;
+ sconfig.format = config->format;
+
+ ret = dfb_surface_lock( surface );
+ if (ret)
+ return ret;
+
+ ret = dfb_surface_reconfig( surface, &sconfig );
+ if (ret) {
+ dfb_surface_unlock( surface );
+ return ret;
+ }
+
+ if (DFB_PIXELFORMAT_IS_INDEXED(surface->config.format) && !surface->palette) {
+ ret = dfb_surface_init_palette( layer->core, surface );
+ if (ret)
+ D_DERROR( ret, "Core/Layers: Could not initialize palette while switching to indexed mode!\n" );
+ }
+
+ switch (config->buffermode) {
+ case DLBM_TRIPLE:
+ case DLBM_BACKVIDEO:
+ surface->buffers[1]->policy = CSP_VIDEOONLY;
+ break;
+
+ case DLBM_BACKSYSTEM:
+ surface->buffers[1]->policy = CSP_SYSTEMONLY;
+ break;
+
+ case DLBM_FRONTONLY:
+ break;
+
+ default:
+ D_BUG("unknown buffermode");
+ return DFB_BUG;
+ }
+
+ if (surface->config.caps & DSCAPS_ROTATED)
+ surface->rotation = context->rotation;
+ else
+ surface->rotation = (context->rotation == 180) ? 180 : 0;
+
+ dfb_surface_unlock( surface );
+
+ return DFB_OK;
+}
+
+static DFBResult
+deallocate_surface( CoreLayer *layer, CoreLayerRegion *region )
+{
+ DFBResult ret;
+ const DisplayLayerFuncs *funcs;
+ CoreSurface *surface;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, layer, region );
+
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->funcs != NULL );
+ D_ASSERT( region != NULL );
+
+ D_ASSUME( region->surface != NULL );
+
+ funcs = layer->funcs;
+ surface = region->surface;
+
+ if (surface) {
+ /* Special deallocation by the driver. */
+ if (funcs->DeallocateSurface) {
+ ret = funcs->DeallocateSurface( layer, layer->driver_data,
+ layer->layer_data,
+ region->region_data, surface );
+ if (ret)
+ return ret;
+ }
+
+ /* Detach the global listener. */
+ dfb_surface_detach_global( surface, &region->surface_reaction );
+
+ /* Unlink from structure. */
+ dfb_surface_unlink( &region->surface );
+ }
+
+ return DFB_OK;
+}
+
+static void
+screen_rectangle( CoreLayerContext *context,
+ const DFBLocation *location,
+ DFBRectangle *rect )
+{
+ DFBResult ret;
+ int width;
+ int height;
+ CoreLayer *layer;
+
+ D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, location, rect );
+
+ D_MAGIC_ASSERT( context, CoreLayerContext );
+ D_ASSERT( location != NULL );
+ D_ASSERT( rect != NULL );
+
+ D_DEBUG_AT( Core_LayerContext, " <- %4.2f,%4.2f-%4.2f,%4.2f\n",
+ location->x, location->y, location->w, location->h );
+
+ layer = dfb_layer_at( context->layer_id );
+ D_ASSERT( layer != NULL );
+ D_ASSERT( layer->screen != NULL );
+
+ ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height );
+ if (ret) {
+ D_WARN( "could not determine mixer/screen dimension of layer %d", context->layer_id );
+
+ rect->x = location->x * 720;
+ rect->y = location->y * 576;
+ rect->w = location->w * 720;
+ rect->h = location->h * 576;
+ }
+ else {
+ rect->x = location->x * width;
+ rect->y = location->y * height;
+ rect->w = location->w * width;
+ rect->h = location->h * height;
+ }
+
+ D_DEBUG_AT( Core_LayerContext, " => %4d,%4d-%4d,%4d\n", DFB_RECTANGLE_VALS(rect) );
+}
+