summaryrefslogtreecommitdiff
path: root/Source/DirectFB/wm/unique/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/wm/unique/context.c')
-rwxr-xr-xSource/DirectFB/wm/unique/context.c711
1 files changed, 711 insertions, 0 deletions
diff --git a/Source/DirectFB/wm/unique/context.c b/Source/DirectFB/wm/unique/context.c
new file mode 100755
index 0000000..cb77b39
--- /dev/null
+++ b/Source/DirectFB/wm/unique/context.c
@@ -0,0 +1,711 @@
+/*
+ (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 <directfb.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/object.h>
+#include <fusion/shmalloc.h>
+
+#include <core/coretypes.h>
+#include <core/input.h>
+#include <core/layer_context.h>
+#include <core/layer_region.h>
+#include <core/layers.h>
+#include <core/layers_internal.h> /* FIXME */
+#include <core/state.h>
+#include <core/surface.h>
+#include <core/windowstack.h>
+#include <core/windows_internal.h> /* FIXME */
+
+#include <gfx/util.h>
+
+#include <misc/conf.h>
+#include <misc/util.h>
+
+#include <unique/context.h>
+#include <unique/device.h>
+#include <unique/input_channel.h>
+#include <unique/input_switch.h>
+#include <unique/internal.h>
+
+
+D_DEBUG_DOMAIN( UniQuE_Context, "UniQuE/Context", "UniQuE's Stack Context" );
+
+
+static const ReactionFunc unique_context_globals[] = {
+ _unique_wm_module_context_listener,
+ NULL
+};
+
+/**************************************************************************************************/
+
+static void
+context_destructor( FusionObject *object, bool zombie, void *ctx )
+{
+ int i;
+ UniqueContext *context = (UniqueContext*) object;
+
+ D_DEBUG_AT( UniQuE_Context, "destroying %p (stack %p)%s\n",
+ context, context->stack, zombie ? " (ZOMBIE)" : "");
+
+ D_ASSUME( fusion_vector_is_empty( &context->windows ) );
+
+ unique_context_notify( context, UCNF_DESTROYED );
+
+ unique_device_detach_global( context->devices[UDCI_POINTER], &context->cursor_reaction );
+
+
+ unique_input_switch_drop( context->input_switch, context->foo_channel );
+
+ unique_input_channel_destroy( context->foo_channel );
+
+ unique_input_switch_destroy( context->input_switch );
+
+
+ for (i=0; i<_UDCI_NUM; i++)
+ unique_device_destroy( context->devices[i] );
+
+
+ while (fusion_vector_has_elements( &context->windows )) {
+ unique_window_destroy( fusion_vector_at( &context->windows, 0 ) );
+ }
+
+ stret_region_destroy( context->root );
+
+
+ fusion_vector_destroy( &context->windows );
+
+ dfb_surface_unlink( &context->surface );
+
+ dfb_layer_region_unlink( &context->region );
+
+ D_MAGIC_CLEAR( context );
+
+ fusion_object_destroy( object );
+}
+
+FusionObjectPool *
+unique_context_pool_create( const FusionWorld *world )
+{
+ return fusion_object_pool_create( "UniQuE Context Pool", sizeof(UniqueContext),
+ sizeof(UniqueContextNotification), context_destructor, NULL, world );
+}
+
+/**************************************************************************************************/
+
+static DFBEnumerationResult
+connect_device( CoreInputDevice *source,
+ void *ctx )
+{
+ UniqueDevice *device = ctx;
+
+ D_MAGIC_ASSERT( device, UniqueDevice );
+
+ unique_device_connect( device, source );
+
+ return DFENUM_OK;
+}
+
+static DFBResult
+create_devices( CoreDFB *core,
+ UniqueContext *context,
+ WMShared *shared )
+{
+ int i;
+ DFBResult ret;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+ D_MAGIC_ASSERT( shared, WMShared );
+
+ for (i=0; i<_UDCI_NUM; i++) {
+ DFBInputDeviceCapabilities caps;
+
+ ret = unique_device_create( core, context, shared->device_classes[i],
+ context, &context->devices[i] );
+ if (ret)
+ goto error;
+
+ ret = unique_input_switch_add( context->input_switch, context->devices[i] );
+ if (ret)
+ goto error_add;
+
+ switch (i) {
+ case UDCI_POINTER:
+ caps = DICAPS_AXES | DICAPS_BUTTONS;
+ break;
+
+ case UDCI_WHEEL:
+ caps = DICAPS_AXES;
+ break;
+
+ case UDCI_KEYBOARD:
+ caps = DICAPS_KEYS;
+ break;
+
+ default:
+ caps = DICAPS_ALL;
+ break;
+ }
+
+ dfb_input_enumerate_devices( connect_device, context->devices[i], caps );
+ }
+
+ return DFB_OK;
+
+
+error_add:
+ unique_device_destroy( context->devices[i] );
+
+error:
+ while (--i >= 0)
+ unique_device_destroy( context->devices[i] );
+
+ return ret;
+}
+
+/**************************************************************************************************/
+
+DFBResult
+unique_context_create( CoreDFB *core,
+ CoreWindowStack *stack,
+ CoreLayerRegion *region,
+ DFBDisplayLayerID layer_id,
+ WMShared *shared,
+ UniqueContext **ret_context )
+{
+ int i;
+ DFBResult ret;
+ UniqueContext *context;
+
+ D_ASSERT( stack != NULL );
+ D_MAGIC_ASSERT( shared, WMShared );
+ D_ASSERT( ret_context != NULL );
+
+ context = unique_wm_create_context();
+ if (!context)
+ return DFB_FUSION;
+
+ context->stack = stack;
+ context->shared = shared;
+ context->layer_id = layer_id;
+ context->color = (DFBColor) { 0xff, 0xa0, 0xd0, 0xf0 };
+ context->shmpool = stack->shmpool;
+
+ fusion_vector_init( &context->windows, 16, context->shmpool );
+
+ /* Create Root Region. */
+ ret = stret_region_create( shared->region_classes[URCI_ROOT], context, 0,
+ SRF_ACTIVE | SRF_OUTPUT, _UNRL_NUM,
+ 0, 0, INT_MAX, INT_MAX,
+ NULL, 0, context->shmpool, &context->root );
+ if (ret)
+ goto error;
+
+ /* Link layer region. */
+ ret = dfb_layer_region_link( &context->region, region );
+ if (ret)
+ goto error;
+
+ /* Get the region's surface. */
+ ret = dfb_layer_region_get_surface( region, &context->surface );
+ if (ret)
+ goto error;
+
+ /* Make it global. */
+ ret = dfb_surface_globalize( context->surface );
+ if (ret) {
+ dfb_surface_unref( context->surface );
+ goto error;
+ }
+
+ D_MAGIC_SET( context, UniqueContext );
+
+ ret = unique_input_switch_create( context, &context->input_switch );
+ if (ret)
+ goto error_switch;
+
+ ret = create_devices( core, context, shared );
+ if (ret)
+ goto error_devices;
+
+ ret = unique_input_channel_create( core, context, &context->foo_channel );
+ if (ret)
+ goto error_foo_channel;
+
+ ret = unique_device_attach_global( context->devices[UDCI_POINTER],
+ UNIQUE_CURSOR_DEVICE_LISTENER,
+ context, &context->cursor_reaction );
+ if (ret)
+ goto error_attach_cursor;
+
+ /* Change global reaction lock. */
+ fusion_object_set_lock( &context->object, &context->stack->context->lock );
+
+ /* Activate Object. */
+ fusion_object_activate( &context->object );
+
+ /* Return new context. */
+ *ret_context = context;
+
+ return DFB_OK;
+
+
+error_attach_cursor:
+ unique_input_channel_destroy( context->foo_channel );
+
+error_foo_channel:
+ for (i=0; i<_UDCI_NUM; i++)
+ unique_device_destroy( context->devices[i] );
+
+error_devices:
+ unique_input_switch_destroy( context->input_switch );
+
+error_switch:
+ D_MAGIC_CLEAR( context );
+
+ dfb_surface_unlink( &context->surface );
+
+error:
+ if (context->region)
+ dfb_layer_region_unlink( &context->region );
+
+ if (context->root)
+ stret_region_destroy( context->root );
+
+ fusion_vector_destroy( &context->windows );
+
+ fusion_object_destroy( &context->object );
+
+ return ret;
+}
+
+DFBResult
+unique_context_notify( UniqueContext *context,
+ UniqueContextNotificationFlags flags )
+{
+ UniqueContextNotification notification;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSERT( flags != UCNF_NONE );
+
+ D_ASSERT( ! (flags & ~UCNF_ALL) );
+
+ notification.flags = flags;
+ notification.context = context;
+
+ return unique_context_dispatch( context, &notification, unique_context_globals );
+}
+
+DFBResult
+unique_context_set_active( UniqueContext *context,
+ bool active )
+{
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSUME( context->active != active );
+
+ if (context->active == active)
+ return DFB_OK;
+
+ context->active = active;
+
+ if (active)
+ return dfb_windowstack_repaint_all( context->stack );
+
+ /* Force release of all pressed keys. */
+ return unique_context_flush_keys( context );
+}
+
+DFBResult
+unique_context_set_color( UniqueContext *context,
+ const DFBColor *color )
+{
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSERT( color != NULL );
+
+ context->color = *color;
+
+ return dfb_windowstack_repaint_all( context->stack );
+}
+
+/* HACK: dumped in here for now, will move into cursor class */
+void
+unique_draw_cursor( CoreWindowStack *stack, UniqueContext *context, CardState *state, DFBRegion *region )
+{
+ DFBRectangle src;
+ DFBSurfaceBlittingFlags flags = DSBLIT_BLEND_ALPHACHANNEL;
+
+ D_ASSERT( stack != NULL );
+ D_MAGIC_ASSERT( context, UniqueContext );
+ D_MAGIC_ASSERT( state, CardState );
+ DFB_REGION_ASSERT( region );
+
+ D_ASSUME( stack->cursor.opacity > 0 );
+
+ /* Initialize source rectangle. */
+ src.x = region->x1 - stack->cursor.x + stack->cursor.hot.x;
+ src.y = region->y1 - stack->cursor.y + stack->cursor.hot.y;
+ src.w = region->x2 - region->x1 + 1;
+ src.h = region->y2 - region->y1 + 1;
+
+ /* Use global alpha blending. */
+ if (stack->cursor.opacity != 0xFF) {
+ flags |= DSBLIT_BLEND_COLORALPHA;
+
+ /* Set opacity as blending factor. */
+ if (state->color.a != stack->cursor.opacity) {
+ state->color.a = stack->cursor.opacity;
+ state->modified |= SMF_COLOR;
+ }
+ }
+
+ /* Different compositing methods depending on destination format. */
+ if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
+ if (DFB_PIXELFORMAT_HAS_ALPHA( state->destination->config.format )) {
+ /*
+ * Always use compliant Porter/Duff SRC_OVER,
+ * if the destination has an alpha channel.
+ *
+ * Cd = destination color (non-premultiplied)
+ * Ad = destination alpha
+ *
+ * Cs = source color (non-premultiplied)
+ * As = source alpha
+ *
+ * Ac = color alpha
+ *
+ * cd = Cd * Ad (premultiply destination)
+ * cs = Cs * As (premultiply source)
+ *
+ * The full equation to calculate resulting color and alpha (premultiplied):
+ *
+ * cx = cd * (1-As*Ac) + cs * Ac
+ * ax = Ad * (1-As*Ac) + As * Ac
+ */
+ dfb_state_set_src_blend( state, DSBF_ONE );
+
+ /* Need to premultiply source with As*Ac or only with Ac? */
+ if (! (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED))
+ flags |= DSBLIT_SRC_PREMULTIPLY;
+ else if (flags & DSBLIT_BLEND_COLORALPHA)
+ flags |= DSBLIT_SRC_PREMULTCOLOR;
+
+ /* Need to premultiply/demultiply destination? */
+// if (! (state->destination->caps & DSCAPS_PREMULTIPLIED))
+// flags |= DSBLIT_DST_PREMULTIPLY | DSBLIT_DEMULTIPLY;
+ }
+ else {
+ /*
+ * We can avoid DSBLIT_SRC_PREMULTIPLY for destinations without an alpha channel
+ * by using another blending function, which is more likely that it's accelerated
+ * than premultiplication at this point in time.
+ *
+ * This way the resulting alpha (ax) doesn't comply with SRC_OVER,
+ * but as the destination doesn't have an alpha channel it's no problem.
+ *
+ * As the destination's alpha value is always 1.0 there's no need for
+ * premultiplication. The resulting alpha value will also be 1.0 without
+ * exceptions, therefore no need for demultiplication.
+ *
+ * cx = Cd * (1-As*Ac) + Cs*As * Ac (still same effect as above)
+ * ax = Ad * (1-As*Ac) + As*As * Ac (wrong, but discarded anyways)
+ */
+ if (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED) {
+ /* Need to premultiply source with Ac? */
+ if (flags & DSBLIT_BLEND_COLORALPHA)
+ flags |= DSBLIT_SRC_PREMULTCOLOR;
+
+ dfb_state_set_src_blend( state, DSBF_ONE );
+ }
+ else
+ dfb_state_set_src_blend( state, DSBF_SRCALPHA );
+ }
+ }
+
+ /* Set blitting flags. */
+ dfb_state_set_blitting_flags( state, flags );
+
+ /* Set blitting source. */
+ state->source = stack->cursor.surface;
+ state->modified |= SMF_SOURCE;
+
+ /* Blit from the window to the region being updated. */
+ dfb_gfxcard_blit( &src, region->x1, region->y1, state );
+
+ /* Reset blitting source. */
+ state->source = NULL;
+ state->modified |= SMF_SOURCE;
+}
+
+DFBResult
+unique_context_update( UniqueContext *context,
+ const DFBRegion *updates,
+ int num,
+ DFBSurfaceFlipFlags flags )
+{
+ int i;
+ CoreLayer *layer;
+ CardState *state;
+ int count = 0;
+ DFBRegion root;
+ DFBRegion regions[num];
+ DFBRegion cursor_inter;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+ D_ASSERT( context->stack != NULL );
+
+ D_ASSERT( updates != NULL );
+ D_ASSERT( num > 0 );
+
+ if (!context->active)
+ return DFB_OK;
+
+ D_DEBUG_AT( UniQuE_Context, "unique_context_update( num %d, flags 0x%08x )\n", num, flags );
+
+ layer = dfb_layer_at( context->layer_id );
+ state = dfb_layer_state( layer );
+
+ root = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, context->width, context->height );
+
+ for (i=0; i<num; i++) {
+ const DFBRegion *region = &updates[i];
+
+ if (!dfb_region_region_intersects( region, &root ))
+ continue;
+
+ regions[count++] = DFB_REGION_INIT_INTERSECTED( region, 0, 0, root.x2, root.y2 );
+
+ D_DEBUG_AT( UniQuE_Context, " (%2d) %4d, %4d - %4dx%4d\n", i,
+ DFB_RECTANGLE_VALS_FROM_REGION( &regions[count-1] ) );
+ }
+
+ if (!count) {
+ D_DEBUG_AT( UniQuE_Context, " -> No intersection with root!\n" );
+ return DFB_OK;
+ }
+
+ /* Set destination. */
+ state->destination = context->surface;
+ state->modified |= SMF_DESTINATION;
+
+ for (i=0; i<count; i++) {
+ const DFBRegion *update = &regions[i];
+
+ /* Set clipping region. */
+ dfb_state_set_clip( state, update );
+
+ /* Compose updated region. */
+ stret_region_update( context->root, update, state );
+
+ /* Update cursor? */
+ cursor_inter = context->cursor_region;
+ if (context->cursor_drawn && dfb_region_region_intersect( &cursor_inter, update )) {
+ DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &cursor_inter );
+
+ D_ASSUME( context->cursor_bs_valid );
+
+ dfb_gfx_copy_to( context->surface, context->cursor_bs, &rect,
+ rect.x - context->cursor_region.x1,
+ rect.y - context->cursor_region.y1, true );
+
+ unique_draw_cursor( context->stack, context, state, &cursor_inter );
+ }
+ }
+
+ /* Reset destination. */
+ state->destination = NULL;
+ state->modified |= SMF_DESTINATION;
+
+ /* Software cursor code relies on a valid back buffer. */
+ if (context->stack->cursor.enabled)
+ flags |= DSFLIP_BLIT;
+
+ /* Flip all updated regions. */
+ for (i=0; i<count; i++) {
+ const DFBRegion *update = &regions[i];
+
+ dfb_layer_region_flip_update( context->region, update, flags );
+ }
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_context_resize( UniqueContext *context,
+ int width,
+ int height )
+{
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ context->width = width;
+ context->height = height;
+
+ stret_region_resize( context->root, width, height );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_context_flush_keys( UniqueContext *context )
+{
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_context_window_at( UniqueContext *context,
+ int x,
+ int y,
+ UniqueWindow **ret_window )
+{
+ int i;
+ CoreWindowStack *stack;
+ WMShared *shared;
+ UniqueWindow *window = NULL;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSERT( ret_window != NULL );
+
+ stack = context->stack;
+ shared = context->shared;
+
+ D_ASSERT( stack != NULL );
+ D_MAGIC_ASSERT( shared, WMShared );
+
+ if (stack->cursor.enabled) {
+ StretRegion *region;
+
+ if (x < 0)
+ x = stack->cursor.x;
+ if (y < 0)
+ y = stack->cursor.y;
+
+ region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
+ if (region && (region->clazz == shared->region_classes[URCI_FOO] ||
+ region->clazz == shared->region_classes[URCI_WINDOW]))
+ {
+ window = stret_region_data( region );
+
+ D_MAGIC_ASSERT( window, UniqueWindow );
+ }
+ }
+ else {
+ fusion_vector_foreach_reverse (window, i, context->windows)
+ if (window->opacity && !(window->options & DWOP_GHOST))
+ break;
+
+ if (i < 0)
+ window = NULL;
+ }
+
+ D_MAGIC_ASSERT_IF( window, UniqueWindow );
+
+ *ret_window = window;
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_context_lookup_window( UniqueContext *context,
+ DFBWindowID window_id,
+ UniqueWindow **ret_window )
+{
+ int i;
+ UniqueWindow *window = NULL;
+
+ D_ASSERT( ret_window != NULL );
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ fusion_vector_foreach_reverse (window, i, context->windows) {
+ if (window->window->id == window_id)
+ break;
+ }
+
+ *ret_window = window;
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_context_enum_windows( UniqueContext *context,
+ CoreWMWindowCallback callback,
+ void *callback_ctx )
+{
+ int i;
+ UniqueWindow *window = NULL;
+
+ D_ASSERT( callback != NULL );
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ fusion_vector_foreach_reverse (window, i, context->windows) {
+ if (callback( window->window, callback_ctx ) != DFENUM_OK)
+ break;
+ }
+
+ return DFB_OK;
+}
+
+/**************************************************************************************************/
+
+ReactionResult
+_unique_cursor_device_listener( const void *msg_data,
+ void *ctx )
+{
+ const UniqueInputEvent *event = msg_data;
+ UniqueContext *context = ctx;
+
+ D_ASSERT( event != NULL );
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_DEBUG_AT( UniQuE_Context, "_unique_cursor_device_listener( %p, %p )\n", event, context );
+
+ switch (event->type) {
+ case UIET_MOTION:
+ dfb_windowstack_cursor_warp( context->stack, event->pointer.x, event->pointer.y );
+ break;
+
+ default:
+ break;
+ }
+
+ return RS_OK;
+}
+