summaryrefslogtreecommitdiff
path: root/Source/DirectFB/wm/unique/input_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/wm/unique/input_switch.c')
-rwxr-xr-xSource/DirectFB/wm/unique/input_switch.c776
1 files changed, 776 insertions, 0 deletions
diff --git a/Source/DirectFB/wm/unique/input_switch.c b/Source/DirectFB/wm/unique/input_switch.c
new file mode 100755
index 0000000..08fa0e2
--- /dev/null
+++ b/Source/DirectFB/wm/unique/input_switch.c
@@ -0,0 +1,776 @@
+/*
+ (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/shmalloc.h>
+#include <fusion/vector.h>
+
+#include <core/input.h>
+#include <core/windowstack.h>
+
+#include <misc/util.h>
+
+#include <unique/device.h>
+#include <unique/input_channel.h>
+#include <unique/input_switch.h>
+#include <unique/internal.h>
+
+
+
+D_DEBUG_DOMAIN( UniQuE_InpSw, "UniQuE/InpSwitch", "UniQuE's Input Switch" );
+
+
+typedef struct {
+ DirectLink link;
+
+ int magic;
+
+ UniqueDevice *device;
+
+ GlobalReaction reaction;
+} SwitchConnection;
+
+/**************************************************************************************************/
+
+static void purge_connection( UniqueInputSwitch *input_switch,
+ SwitchConnection *connection );
+
+static bool target_switch ( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel );
+
+static bool update_targets ( UniqueInputSwitch *input_switch );
+
+/**************************************************************************************************/
+
+DFBResult
+unique_input_switch_create( UniqueContext *context,
+ UniqueInputSwitch **ret_switch )
+{
+ int i;
+ WMShared *shared;
+ UniqueInputSwitch *input_switch;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_create( context %p )\n", context );
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSERT( ret_switch != NULL );
+
+ shared = context->shared;
+
+ D_MAGIC_ASSERT( shared, WMShared );
+
+ /* Allocate switch data. */
+ input_switch = SHCALLOC( context->shmpool, 1, sizeof(UniqueInputSwitch) );
+ if (!input_switch) {
+ D_WARN( "out of (shared) memory" );
+ return D_OOSHM();
+ }
+
+ /* Initialize input_switch data. */
+ input_switch->context = context;
+
+ /* Set class ID of each target. */
+ for (i=0; i<_UDCI_NUM; i++)
+ input_switch->targets[i].clazz = shared->device_classes[i];
+
+ D_MAGIC_SET( input_switch, UniqueInputSwitch );
+
+ D_DEBUG_AT( UniQuE_InpSw, " -> input_switch created (%p)\n", input_switch );
+
+ *ret_switch = input_switch;
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_destroy( UniqueInputSwitch *input_switch )
+{
+ int i;
+ DirectLink *n;
+ SwitchConnection *connection;
+ UniqueContext *context;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_destroy( %p )\n", input_switch );
+
+ direct_list_foreach_safe (connection, n, input_switch->connections) {
+ D_MAGIC_ASSERT( connection, SwitchConnection );
+
+ purge_connection( input_switch, connection );
+ }
+
+ D_ASSERT( input_switch->connections == NULL );
+
+ for (i=0; i<_UDCI_NUM; i++) {
+ UniqueInputFilter *filter;
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ direct_list_foreach_safe (filter, n, target->filters) {
+ D_MAGIC_ASSERT( filter, UniqueInputFilter );
+ D_MAGIC_ASSERT( filter->channel, UniqueInputChannel );
+
+ D_DEBUG_AT( UniQuE_InpSw, " -> filter %p, index %d, channel %p\n",
+ filter, filter->index, filter->channel );
+
+ direct_list_remove( &target->filters, &filter->link );
+
+ D_MAGIC_CLEAR( filter );
+
+ SHFREE( context->shmpool, filter );
+ }
+
+ D_ASSERT( target->filters == NULL );
+ }
+
+ D_MAGIC_CLEAR( input_switch );
+
+ SHFREE( context->shmpool, input_switch );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_add( UniqueInputSwitch *input_switch,
+ UniqueDevice *device )
+{
+ DFBResult ret;
+ SwitchConnection *connection;
+ UniqueContext *context;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( device, UniqueDevice );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_add( %p, %p )\n", input_switch, device );
+
+ /* Allocate connection structure. */
+ connection = SHCALLOC( context->shmpool, 1, sizeof(SwitchConnection) );
+ if (!connection) {
+ D_WARN( "out of (shared) memory" );
+ return D_OOSHM();
+ }
+
+ /* Initialize connection structure. */
+ connection->device = device;
+
+ /* Attach global reaction for processing events. */
+ ret = unique_device_attach_global( device, UNIQUE_INPUT_SWITCH_DEVICE_LISTENER,
+ input_switch, &connection->reaction );
+ if (ret) {
+ D_DERROR( ret, "UniQuE/InpSwitch: Could not attach global device reaction!\n" );
+ SHFREE( context->shmpool, connection );
+ return ret;
+ }
+
+ /* Add the new connection to the list. */
+ direct_list_append( &input_switch->connections, &connection->link );
+
+ D_MAGIC_SET( connection, SwitchConnection );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_remove( UniqueInputSwitch *input_switch,
+ UniqueDevice *device )
+{
+ SwitchConnection *connection;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( device, UniqueDevice );
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_remove( %p, %p )\n", input_switch, device );
+
+ direct_list_foreach (connection, input_switch->connections) {
+ D_MAGIC_ASSERT( connection, SwitchConnection );
+
+ if (connection->device == device)
+ break;
+ }
+
+ if (!connection) {
+ D_WARN( "device not found amoung connections" );
+ return DFB_ITEMNOTFOUND;
+ }
+
+ purge_connection( input_switch, connection );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_select( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel )
+{
+ UniqueInputTarget *target;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_select( %p, %d, %p )\n",
+ input_switch, index, channel );
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < _UDCI_NUM );
+
+ target = &input_switch->targets[index];
+
+ target->normal = channel;
+
+ if (!target->fixed && !target->implicit)
+ target_switch( input_switch, index, channel );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_set( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel )
+{
+ UniqueInputTarget *target;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_set( %p, %d, %p )\n",
+ input_switch, index, channel );
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < _UDCI_NUM );
+
+ target = &input_switch->targets[index];
+
+ if (target->fixed)
+ return DFB_BUSY;
+
+ target->fixed = channel;
+
+ target_switch( input_switch, index, channel );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_unset( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel )
+{
+ UniqueInputTarget *target;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_unset( %p, %d, %p )\n",
+ input_switch, index, channel );
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < _UDCI_NUM );
+
+ target = &input_switch->targets[index];
+
+ if (target->fixed != channel)
+ return DFB_ACCESSDENIED;
+
+ target->fixed = NULL;
+
+
+ update_targets( input_switch );
+ //target_switch( input_switch, index, target->normal );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_set_filter( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel,
+ const UniqueInputEvent *event,
+ UniqueInputFilter **ret_filter )
+{
+ UniqueInputFilter *filter;
+ UniqueInputTarget *target;
+ UniqueContext *context;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_set_filter( %p, %d, %p, %p )\n",
+ input_switch, index, channel, event );
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < _UDCI_NUM );
+
+ D_ASSERT( event != NULL );
+ D_ASSERT( ret_filter != NULL );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ target = &input_switch->targets[index];
+
+ direct_list_foreach (filter, target->filters) {
+ D_MAGIC_ASSERT( filter, UniqueInputFilter );
+
+ if (unique_device_filter( target->clazz, event, &filter->filter ))
+ return DFB_BUSY;
+ }
+
+ /* Allocate new filter. */
+ filter = SHCALLOC( context->shmpool, 1, sizeof(UniqueInputFilter) );
+ if (!filter)
+ return D_OOSHM();
+
+ filter->index = index;
+ filter->channel = channel;
+ filter->filter = *event;
+
+ direct_list_append( &target->filters, &filter->link );
+
+ D_MAGIC_SET( filter, UniqueInputFilter );
+
+ *ret_filter = filter;
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_unset_filter( UniqueInputSwitch *input_switch,
+ UniqueInputFilter *filter )
+{
+ UniqueInputTarget *target;
+ UniqueContext *context;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_unset_filter( %p, %p )\n",
+ input_switch, filter );
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( filter, UniqueInputFilter );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ D_ASSERT( filter->index >= 0 );
+ D_ASSERT( filter->index < _UDCI_NUM );
+
+ target = &input_switch->targets[filter->index];
+
+ direct_list_remove( &target->filters, &filter->link );
+
+ D_MAGIC_CLEAR( filter );
+
+ SHFREE( context->shmpool, filter );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_drop( UniqueInputSwitch *input_switch,
+ UniqueInputChannel *channel )
+{
+ int i;
+ UniqueContext *context;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_drop( %p, %p )\n", input_switch, channel );
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ for (i=0; i<_UDCI_NUM; i++) {
+ DirectLink *n;
+ UniqueInputFilter *filter;
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ if (target->normal == channel)
+ target->normal = NULL;
+
+ if (target->fixed == channel)
+ target->fixed = NULL;
+
+ if (target->implicit == channel)
+ target->implicit = NULL;
+
+ if (target->current == channel)
+ target->current = NULL;
+
+ D_DEBUG_AT( UniQuE_InpSw, " -> index %d, filters %p\n", i, target->filters );
+
+ direct_list_foreach_safe (filter, n, target->filters) {
+ D_MAGIC_ASSERT( filter, UniqueInputFilter );
+ D_MAGIC_ASSERT( filter->channel, UniqueInputChannel );
+
+ D_DEBUG_AT( UniQuE_InpSw,
+ " -> filter %p, channel %p\n", filter, filter->channel );
+
+ D_ASSUME( filter->channel != channel );
+
+ if (filter->channel == channel) {
+ direct_list_remove( &target->filters, &filter->link );
+
+ D_MAGIC_CLEAR( filter );
+
+ SHFREE( context->shmpool, filter );
+ }
+ }
+ }
+
+ if (!input_switch->targets[UDCI_POINTER].fixed)
+ update_targets( input_switch );
+
+ return DFB_OK;
+}
+
+DFBResult
+unique_input_switch_update( UniqueInputSwitch *input_switch,
+ UniqueInputChannel *channel )
+{
+ int x, y, i;
+ StretRegion *region;
+ UniqueContext *context;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+
+ x = input_switch->x;
+ y = input_switch->y;
+
+ D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_update( %d, %d )\n", x, y );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
+ if (region) {
+ for (i=0; i<_UDCI_NUM; i++) {
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ if (target->normal == channel)
+ stret_region_get_input( region, i, x, y, &target->normal );
+ }
+ }
+ else {
+ for (i=0; i<_UDCI_NUM; i++) {
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ if (target->normal == channel)
+ target->normal = NULL;
+ }
+ }
+
+ for (i=0; i<_UDCI_NUM; i++) {
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ target_switch( input_switch, i, target->fixed ? : target->implicit ? : target->normal );
+ }
+
+ return DFB_OK;
+}
+
+/**************************************************************************************************/
+
+static bool
+target_switch( UniqueInputSwitch *input_switch,
+ UniqueDeviceClassIndex index,
+ UniqueInputChannel *channel )
+{
+ UniqueInputEvent evt;
+ UniqueInputTarget *target;
+ UniqueInputChannel *current;
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < _UDCI_NUM );
+
+ target = &input_switch->targets[index];
+
+ current = target->current;
+
+ D_MAGIC_ASSERT_IF( channel, UniqueInputChannel );
+ D_MAGIC_ASSERT_IF( current, UniqueInputChannel );
+
+ if (channel == current)
+ return false;
+
+ D_DEBUG_AT( UniQuE_InpSw, "target_switch( index %d, x %d, y %d, channel %p )\n",
+ index, input_switch->x, input_switch->y, channel );
+
+ evt.type = UIET_CHANNEL;
+
+ evt.channel.index = index;
+ evt.channel.x = input_switch->x;
+ evt.channel.y = input_switch->y;
+
+ if (current) {
+ evt.channel.selected = false;
+
+ unique_input_channel_dispatch( current, &evt );
+ }
+
+ target->current = channel;
+
+ if (channel) {
+ evt.channel.selected = true;
+
+ unique_input_channel_dispatch( channel, &evt );
+ }
+
+ return true;
+}
+
+static void
+target_dispatch( UniqueInputTarget *target,
+ const UniqueInputEvent *event )
+{
+ UniqueInputFilter *filter;
+ UniqueInputChannel *channel;
+
+ D_ASSERT( target != NULL );
+ D_ASSERT( event != NULL );
+
+ channel = target->current;
+
+ D_MAGIC_ASSERT_IF( channel, UniqueInputChannel );
+
+
+ direct_list_foreach (filter, target->filters) {
+ D_MAGIC_ASSERT( filter, UniqueInputFilter );
+
+ if (unique_device_filter( target->clazz, event, &filter->filter )) {
+ channel = filter->channel;
+
+ D_MAGIC_ASSERT( channel, UniqueInputChannel );
+
+ break;
+ }
+ }
+
+ if (channel)
+ unique_input_channel_dispatch( channel, event );
+ else
+ D_DEBUG_AT( UniQuE_InpSw, "target_dispatch( class %d ) "
+ "<- no selected channel, dropping event.\n", target->clazz );
+}
+
+static bool
+update_targets( UniqueInputSwitch *input_switch )
+{
+ int x, y, i;
+ StretRegion *region;
+ UniqueContext *context;
+ bool updated[_UDCI_NUM];
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+
+ x = input_switch->x;
+ y = input_switch->y;
+
+ D_DEBUG_AT( UniQuE_InpSw, "update_targets( %d, %d )\n", x, y );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
+ if (region) {
+ for (i=0; i<_UDCI_NUM; i++)
+ stret_region_get_input( region, i, x, y, &input_switch->targets[i].normal );
+ }
+ else {
+ for (i=0; i<_UDCI_NUM; i++)
+ input_switch->targets[i].normal = NULL;
+ }
+
+ for (i=0; i<_UDCI_NUM; i++) {
+ UniqueInputTarget *target = &input_switch->targets[i];
+
+ updated[i] = target_switch( input_switch, i,
+ target->fixed ? : target->implicit ? : target->normal );
+ }
+
+ return updated[UDCI_POINTER];
+}
+
+ReactionResult
+_unique_input_switch_device_listener( const void *msg_data,
+ void *ctx )
+{
+ const UniqueInputEvent *event = msg_data;
+ UniqueInputSwitch *inpsw = ctx;
+ UniqueInputTarget *target = NULL;
+ UniqueContext *context;
+
+ (void) event;
+ (void) inpsw;
+
+ D_ASSERT( event != NULL );
+
+ D_MAGIC_ASSERT( inpsw, UniqueInputSwitch );
+
+ context = inpsw->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ if (dfb_windowstack_lock( context->stack ))
+ return RS_OK;
+
+ if (!context->active) {
+ dfb_windowstack_unlock( context->stack );
+ return RS_OK;
+ }
+
+ D_DEBUG_AT( UniQuE_InpSw, "_unique_input_switch_device_listener( %p, %p )\n",
+ event, inpsw );
+
+ switch (event->type) {
+ case UIET_MOTION:
+ target = &inpsw->targets[UDCI_POINTER];
+
+ inpsw->x = event->pointer.x;
+ inpsw->y = event->pointer.y;
+
+ if (!target->fixed && !target->implicit && update_targets( inpsw ))
+ break;
+
+ target_dispatch( target, event );
+ break;
+
+ case UIET_BUTTON:
+ target = &inpsw->targets[UDCI_POINTER];
+
+ if (event->pointer.press && !target->implicit) {
+ D_DEBUG_AT( UniQuE_InpSw, " -> implicit pointer grab, %p\n", target->current );
+
+ target->implicit = target->current;
+ }
+
+ target_dispatch( target, event );
+
+ if (!event->pointer.press && !event->pointer.buttons) {
+ D_ASSUME( target->implicit != NULL );
+
+ if (target->implicit) {
+ D_DEBUG_AT( UniQuE_InpSw, " -> implicit pointer ungrab, %p\n", target->implicit );
+
+ target->implicit = NULL;
+
+ if (!target->fixed)
+ update_targets( inpsw );
+ }
+ }
+ break;
+
+ case UIET_WHEEL:
+ target_dispatch( &inpsw->targets[UDCI_WHEEL], event );
+ break;
+
+ case UIET_KEY:
+ target = &inpsw->targets[UDCI_KEYBOARD];
+
+ if (event->keyboard.press && !target->implicit) {
+ D_DEBUG_AT( UniQuE_InpSw, " -> implicit keyboard grab, %p\n", target->current );
+
+ target->implicit = target->current;
+ }
+
+ target_dispatch( target, event );
+
+ if (!event->keyboard.press && !event->keyboard.modifiers) {
+ //D_ASSUME( target->implicit != NULL );
+
+ if (target->implicit) {
+ D_DEBUG_AT( UniQuE_InpSw, " -> implicit keyboard ungrab, %p\n", target->implicit );
+
+ if (!target->fixed)
+ target_switch( inpsw, UDCI_KEYBOARD, target->normal );
+
+ target->implicit = NULL;
+ }
+ }
+ break;
+
+ default:
+ D_ONCE( "unknown event type" );
+ break;
+ }
+
+ dfb_windowstack_unlock( context->stack );
+
+ return RS_OK;
+}
+
+/**************************************************************************************************/
+
+static void
+purge_connection( UniqueInputSwitch *input_switch,
+ SwitchConnection *connection )
+{
+ UniqueContext *context;
+
+ D_DEBUG_AT( UniQuE_InpSw, "purge_connection( %p, %p )\n", input_switch, connection );
+
+ D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
+ D_MAGIC_ASSERT( connection, SwitchConnection );
+
+ context = input_switch->context;
+
+ D_MAGIC_ASSERT( context, UniqueContext );
+
+ /* Detach global reaction for receiving events. */
+ unique_device_detach_global( connection->device, &connection->reaction );
+
+ direct_list_remove( &input_switch->connections, &connection->link );
+
+ D_MAGIC_CLEAR( connection );
+
+ SHFREE( context->shmpool, connection );
+}
+