1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <directfb.h>
32 
33 #include <direct/debug.h>
34 #include <direct/messages.h>
35 #include <direct/util.h>
36 
37 #include <fusion/shmalloc.h>
38 #include <fusion/vector.h>
39 
40 #include <core/input.h>
41 #include <core/windowstack.h>
42 
43 #include <misc/util.h>
44 
45 #include <unique/device.h>
46 #include <unique/input_channel.h>
47 #include <unique/input_switch.h>
48 #include <unique/internal.h>
49 
50 
51 
52 D_DEBUG_DOMAIN( UniQuE_InpSw, "UniQuE/InpSwitch", "UniQuE's Input Switch" );
53 
54 
55 typedef struct {
56      DirectLink       link;
57 
58      int              magic;
59 
60      UniqueDevice    *device;
61 
62      GlobalReaction   reaction;
63 } SwitchConnection;
64 
65 /**************************************************************************************************/
66 
67 static void purge_connection( UniqueInputSwitch      *input_switch,
68                               SwitchConnection       *connection );
69 
70 static bool target_switch   ( UniqueInputSwitch      *input_switch,
71                               UniqueDeviceClassIndex  index,
72                               UniqueInputChannel     *channel );
73 
74 static bool update_targets  ( UniqueInputSwitch      *input_switch );
75 
76 /**************************************************************************************************/
77 
78 DFBResult
unique_input_switch_create(UniqueContext * context,UniqueInputSwitch ** ret_switch)79 unique_input_switch_create( UniqueContext      *context,
80                             UniqueInputSwitch **ret_switch )
81 {
82      int                i;
83      WMShared          *shared;
84      UniqueInputSwitch *input_switch;
85 
86      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_create( context %p )\n", context );
87 
88      D_MAGIC_ASSERT( context, UniqueContext );
89 
90      D_ASSERT( ret_switch != NULL );
91 
92      shared = context->shared;
93 
94      D_MAGIC_ASSERT( shared, WMShared );
95 
96      /* Allocate switch data. */
97      input_switch = SHCALLOC( context->shmpool, 1, sizeof(UniqueInputSwitch) );
98      if (!input_switch) {
99           D_WARN( "out of (shared) memory" );
100           return D_OOSHM();
101      }
102 
103      /* Initialize input_switch data. */
104      input_switch->context = context;
105 
106      /* Set class ID of each target. */
107      for (i=0; i<_UDCI_NUM; i++)
108           input_switch->targets[i].clazz = shared->device_classes[i];
109 
110      D_MAGIC_SET( input_switch, UniqueInputSwitch );
111 
112      D_DEBUG_AT( UniQuE_InpSw, "  -> input_switch created (%p)\n", input_switch );
113 
114      *ret_switch = input_switch;
115 
116      return DFB_OK;
117 }
118 
119 DFBResult
unique_input_switch_destroy(UniqueInputSwitch * input_switch)120 unique_input_switch_destroy( UniqueInputSwitch *input_switch )
121 {
122      int               i;
123      DirectLink       *n;
124      SwitchConnection *connection;
125      UniqueContext    *context;
126 
127      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
128 
129      context = input_switch->context;
130 
131      D_MAGIC_ASSERT( context, UniqueContext );
132 
133      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_destroy( %p )\n", input_switch );
134 
135      direct_list_foreach_safe (connection, n, input_switch->connections) {
136           D_MAGIC_ASSERT( connection, SwitchConnection );
137 
138           purge_connection( input_switch, connection );
139      }
140 
141      D_ASSERT( input_switch->connections == NULL );
142 
143      for (i=0; i<_UDCI_NUM; i++) {
144           UniqueInputFilter *filter;
145           UniqueInputTarget *target = &input_switch->targets[i];
146 
147           direct_list_foreach_safe (filter, n, target->filters) {
148                D_MAGIC_ASSERT( filter, UniqueInputFilter );
149                D_MAGIC_ASSERT( filter->channel, UniqueInputChannel );
150 
151                D_DEBUG_AT( UniQuE_InpSw, "  -> filter %p, index %d, channel %p\n",
152                            filter, filter->index, filter->channel );
153 
154                direct_list_remove( &target->filters, &filter->link );
155 
156                D_MAGIC_CLEAR( filter );
157 
158                SHFREE( context->shmpool, filter );
159           }
160 
161           D_ASSERT( target->filters == NULL );
162      }
163 
164      D_MAGIC_CLEAR( input_switch );
165 
166      SHFREE( context->shmpool, input_switch );
167 
168      return DFB_OK;
169 }
170 
171 DFBResult
unique_input_switch_add(UniqueInputSwitch * input_switch,UniqueDevice * device)172 unique_input_switch_add( UniqueInputSwitch *input_switch,
173                          UniqueDevice      *device )
174 {
175      DFBResult         ret;
176      SwitchConnection *connection;
177      UniqueContext    *context;
178 
179      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
180      D_MAGIC_ASSERT( device, UniqueDevice );
181 
182      context = input_switch->context;
183 
184      D_MAGIC_ASSERT( context, UniqueContext );
185 
186      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_add( %p, %p )\n", input_switch, device );
187 
188      /* Allocate connection structure. */
189      connection = SHCALLOC( context->shmpool, 1, sizeof(SwitchConnection) );
190      if (!connection) {
191           D_WARN( "out of (shared) memory" );
192           return D_OOSHM();
193      }
194 
195      /* Initialize connection structure. */
196      connection->device = device;
197 
198      /* Attach global reaction for processing events. */
199      ret = unique_device_attach_global( device, UNIQUE_INPUT_SWITCH_DEVICE_LISTENER,
200                                         input_switch, &connection->reaction );
201      if (ret) {
202           D_DERROR( ret, "UniQuE/InpSwitch: Could not attach global device reaction!\n" );
203           SHFREE( context->shmpool, connection );
204           return ret;
205      }
206 
207      /* Add the new connection to the list. */
208      direct_list_append( &input_switch->connections, &connection->link );
209 
210      D_MAGIC_SET( connection, SwitchConnection );
211 
212      return DFB_OK;
213 }
214 
215 DFBResult
unique_input_switch_remove(UniqueInputSwitch * input_switch,UniqueDevice * device)216 unique_input_switch_remove( UniqueInputSwitch *input_switch,
217                             UniqueDevice      *device )
218 {
219      SwitchConnection *connection;
220 
221      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
222      D_MAGIC_ASSERT( device, UniqueDevice );
223 
224      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_remove( %p, %p )\n", input_switch, device );
225 
226      direct_list_foreach (connection, input_switch->connections) {
227           D_MAGIC_ASSERT( connection, SwitchConnection );
228 
229           if (connection->device == device)
230                break;
231      }
232 
233      if (!connection) {
234           D_WARN( "device not found amoung connections" );
235           return DFB_ITEMNOTFOUND;
236      }
237 
238      purge_connection( input_switch, connection );
239 
240      return DFB_OK;
241 }
242 
243 DFBResult
unique_input_switch_select(UniqueInputSwitch * input_switch,UniqueDeviceClassIndex index,UniqueInputChannel * channel)244 unique_input_switch_select( UniqueInputSwitch      *input_switch,
245                             UniqueDeviceClassIndex  index,
246                             UniqueInputChannel     *channel )
247 {
248      UniqueInputTarget *target;
249 
250      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
251      D_MAGIC_ASSERT( channel, UniqueInputChannel );
252 
253      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_select( %p, %d, %p )\n",
254                  input_switch, index, channel );
255 
256      D_ASSERT( index >= 0 );
257      D_ASSERT( index < _UDCI_NUM );
258 
259      target = &input_switch->targets[index];
260 
261      target->normal = channel;
262 
263      if (!target->fixed && !target->implicit)
264           target_switch( input_switch, index, channel );
265 
266      return DFB_OK;
267 }
268 
269 DFBResult
unique_input_switch_set(UniqueInputSwitch * input_switch,UniqueDeviceClassIndex index,UniqueInputChannel * channel)270 unique_input_switch_set( UniqueInputSwitch      *input_switch,
271                          UniqueDeviceClassIndex  index,
272                          UniqueInputChannel     *channel )
273 {
274      UniqueInputTarget *target;
275 
276      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
277      D_MAGIC_ASSERT( channel, UniqueInputChannel );
278 
279      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_set( %p, %d, %p )\n",
280                  input_switch, index, channel );
281 
282      D_ASSERT( index >= 0 );
283      D_ASSERT( index < _UDCI_NUM );
284 
285      target = &input_switch->targets[index];
286 
287      if (target->fixed)
288           return DFB_BUSY;
289 
290      target->fixed = channel;
291 
292      target_switch( input_switch, index, channel );
293 
294      return DFB_OK;
295 }
296 
297 DFBResult
unique_input_switch_unset(UniqueInputSwitch * input_switch,UniqueDeviceClassIndex index,UniqueInputChannel * channel)298 unique_input_switch_unset( UniqueInputSwitch      *input_switch,
299                            UniqueDeviceClassIndex  index,
300                            UniqueInputChannel     *channel )
301 {
302      UniqueInputTarget *target;
303 
304      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_unset( %p, %d, %p )\n",
305                  input_switch, index, channel );
306 
307      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
308      D_MAGIC_ASSERT( channel, UniqueInputChannel );
309 
310      D_ASSERT( index >= 0 );
311      D_ASSERT( index < _UDCI_NUM );
312 
313      target = &input_switch->targets[index];
314 
315      if (target->fixed != channel)
316           return DFB_ACCESSDENIED;
317 
318      target->fixed = NULL;
319 
320 
321      update_targets( input_switch );
322      //target_switch( input_switch, index, target->normal );
323 
324      return DFB_OK;
325 }
326 
327 DFBResult
unique_input_switch_set_filter(UniqueInputSwitch * input_switch,UniqueDeviceClassIndex index,UniqueInputChannel * channel,const UniqueInputEvent * event,UniqueInputFilter ** ret_filter)328 unique_input_switch_set_filter( UniqueInputSwitch       *input_switch,
329                                 UniqueDeviceClassIndex   index,
330                                 UniqueInputChannel      *channel,
331                                 const UniqueInputEvent  *event,
332                                 UniqueInputFilter      **ret_filter )
333 {
334      UniqueInputFilter *filter;
335      UniqueInputTarget *target;
336      UniqueContext     *context;
337 
338      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_set_filter( %p, %d, %p, %p )\n",
339                  input_switch, index, channel, event );
340 
341      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
342      D_MAGIC_ASSERT( channel, UniqueInputChannel );
343 
344      D_ASSERT( index >= 0 );
345      D_ASSERT( index < _UDCI_NUM );
346 
347      D_ASSERT( event != NULL );
348      D_ASSERT( ret_filter != NULL );
349 
350      context = input_switch->context;
351 
352      D_MAGIC_ASSERT( context, UniqueContext );
353 
354      target = &input_switch->targets[index];
355 
356      direct_list_foreach (filter, target->filters) {
357           D_MAGIC_ASSERT( filter, UniqueInputFilter );
358 
359           if (unique_device_filter( target->clazz, event, &filter->filter ))
360                return DFB_BUSY;
361      }
362 
363      /* Allocate new filter. */
364      filter = SHCALLOC( context->shmpool, 1, sizeof(UniqueInputFilter) );
365      if (!filter)
366           return D_OOSHM();
367 
368      filter->index   = index;
369      filter->channel = channel;
370      filter->filter  = *event;
371 
372      direct_list_append( &target->filters, &filter->link );
373 
374      D_MAGIC_SET( filter, UniqueInputFilter );
375 
376      *ret_filter = filter;
377 
378      return DFB_OK;
379 }
380 
381 DFBResult
unique_input_switch_unset_filter(UniqueInputSwitch * input_switch,UniqueInputFilter * filter)382 unique_input_switch_unset_filter( UniqueInputSwitch *input_switch,
383                                   UniqueInputFilter *filter )
384 {
385      UniqueInputTarget *target;
386      UniqueContext     *context;
387 
388      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_unset_filter( %p, %p )\n",
389                  input_switch, filter );
390 
391      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
392      D_MAGIC_ASSERT( filter, UniqueInputFilter );
393 
394      context = input_switch->context;
395 
396      D_MAGIC_ASSERT( context, UniqueContext );
397 
398      D_ASSERT( filter->index >= 0 );
399      D_ASSERT( filter->index < _UDCI_NUM );
400 
401      target = &input_switch->targets[filter->index];
402 
403      direct_list_remove( &target->filters, &filter->link );
404 
405      D_MAGIC_CLEAR( filter );
406 
407      SHFREE( context->shmpool, filter );
408 
409      return DFB_OK;
410 }
411 
412 DFBResult
unique_input_switch_drop(UniqueInputSwitch * input_switch,UniqueInputChannel * channel)413 unique_input_switch_drop( UniqueInputSwitch  *input_switch,
414                           UniqueInputChannel *channel )
415 {
416      int            i;
417      UniqueContext *context;
418 
419      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_drop( %p, %p )\n", input_switch, channel );
420 
421      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
422      D_MAGIC_ASSERT( channel, UniqueInputChannel );
423 
424      context = input_switch->context;
425 
426      D_MAGIC_ASSERT( context, UniqueContext );
427 
428      for (i=0; i<_UDCI_NUM; i++) {
429           DirectLink        *n;
430           UniqueInputFilter *filter;
431           UniqueInputTarget *target = &input_switch->targets[i];
432 
433           if (target->normal == channel)
434                target->normal = NULL;
435 
436           if (target->fixed == channel)
437                target->fixed = NULL;
438 
439           if (target->implicit == channel)
440                target->implicit = NULL;
441 
442           if (target->current == channel)
443                target->current = NULL;
444 
445           D_DEBUG_AT( UniQuE_InpSw, "  -> index %d, filters %p\n", i, target->filters );
446 
447           direct_list_foreach_safe (filter, n, target->filters) {
448                D_MAGIC_ASSERT( filter, UniqueInputFilter );
449                D_MAGIC_ASSERT( filter->channel, UniqueInputChannel );
450 
451                D_DEBUG_AT( UniQuE_InpSw,
452                            "  -> filter %p, channel %p\n", filter, filter->channel );
453 
454                D_ASSUME( filter->channel != channel );
455 
456                if (filter->channel == channel) {
457                     direct_list_remove( &target->filters, &filter->link );
458 
459                     D_MAGIC_CLEAR( filter );
460 
461                     SHFREE( context->shmpool, filter );
462                }
463           }
464      }
465 
466      if (!input_switch->targets[UDCI_POINTER].fixed)
467           update_targets( input_switch );
468 
469      return DFB_OK;
470 }
471 
472 DFBResult
unique_input_switch_update(UniqueInputSwitch * input_switch,UniqueInputChannel * channel)473 unique_input_switch_update( UniqueInputSwitch  *input_switch,
474                             UniqueInputChannel *channel )
475 {
476      int            x, y, i;
477      StretRegion   *region;
478      UniqueContext *context;
479 
480      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
481 
482      x = input_switch->x;
483      y = input_switch->y;
484 
485      D_DEBUG_AT( UniQuE_InpSw, "unique_input_switch_update( %d, %d )\n", x, y );
486 
487      context = input_switch->context;
488 
489      D_MAGIC_ASSERT( context, UniqueContext );
490 
491      region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
492      if (region) {
493           for (i=0; i<_UDCI_NUM; i++) {
494                UniqueInputTarget *target = &input_switch->targets[i];
495 
496                if (target->normal == channel)
497                     stret_region_get_input( region, i, x, y, &target->normal );
498           }
499      }
500      else {
501           for (i=0; i<_UDCI_NUM; i++) {
502                UniqueInputTarget *target = &input_switch->targets[i];
503 
504                if (target->normal == channel)
505                     target->normal = NULL;
506           }
507      }
508 
509      for (i=0; i<_UDCI_NUM; i++) {
510           UniqueInputTarget *target = &input_switch->targets[i];
511 
512           target_switch( input_switch, i, target->fixed ? : target->implicit ? : target->normal );
513      }
514 
515      return DFB_OK;
516 }
517 
518 /**************************************************************************************************/
519 
520 static bool
target_switch(UniqueInputSwitch * input_switch,UniqueDeviceClassIndex index,UniqueInputChannel * channel)521 target_switch( UniqueInputSwitch      *input_switch,
522                UniqueDeviceClassIndex  index,
523                UniqueInputChannel     *channel )
524 {
525      UniqueInputEvent    evt;
526      UniqueInputTarget  *target;
527      UniqueInputChannel *current;
528 
529      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
530      D_ASSERT( index >= 0 );
531      D_ASSERT( index < _UDCI_NUM );
532 
533      target = &input_switch->targets[index];
534 
535      current = target->current;
536 
537      D_MAGIC_ASSERT_IF( channel, UniqueInputChannel );
538      D_MAGIC_ASSERT_IF( current, UniqueInputChannel );
539 
540      if (channel == current)
541           return false;
542 
543      D_DEBUG_AT( UniQuE_InpSw, "target_switch( index %d, x %d, y %d, channel %p )\n",
544                  index, input_switch->x, input_switch->y, channel );
545 
546      evt.type = UIET_CHANNEL;
547 
548      evt.channel.index = index;
549      evt.channel.x     = input_switch->x;
550      evt.channel.y     = input_switch->y;
551 
552      if (current) {
553           evt.channel.selected = false;
554 
555           unique_input_channel_dispatch( current, &evt );
556      }
557 
558      target->current = channel;
559 
560      if (channel) {
561           evt.channel.selected = true;
562 
563           unique_input_channel_dispatch( channel, &evt );
564      }
565 
566      return true;
567 }
568 
569 static void
target_dispatch(UniqueInputTarget * target,const UniqueInputEvent * event)570 target_dispatch( UniqueInputTarget      *target,
571                  const UniqueInputEvent *event )
572 {
573      UniqueInputFilter  *filter;
574      UniqueInputChannel *channel;
575 
576      D_ASSERT( target != NULL );
577      D_ASSERT( event != NULL );
578 
579      channel = target->current;
580 
581      D_MAGIC_ASSERT_IF( channel, UniqueInputChannel );
582 
583 
584      direct_list_foreach (filter, target->filters) {
585           D_MAGIC_ASSERT( filter, UniqueInputFilter );
586 
587           if (unique_device_filter( target->clazz, event, &filter->filter )) {
588                channel = filter->channel;
589 
590                D_MAGIC_ASSERT( channel, UniqueInputChannel );
591 
592                break;
593           }
594      }
595 
596      if (channel)
597           unique_input_channel_dispatch( channel, event );
598      else
599           D_DEBUG_AT( UniQuE_InpSw, "target_dispatch( class %d ) "
600                       "<- no selected channel, dropping event.\n", target->clazz );
601 }
602 
603 static bool
update_targets(UniqueInputSwitch * input_switch)604 update_targets( UniqueInputSwitch *input_switch )
605 {
606      int            x, y, i;
607      StretRegion   *region;
608      UniqueContext *context;
609      bool           updated[_UDCI_NUM];
610 
611      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
612 
613      x = input_switch->x;
614      y = input_switch->y;
615 
616      D_DEBUG_AT( UniQuE_InpSw, "update_targets( %d, %d )\n", x, y );
617 
618      context = input_switch->context;
619 
620      D_MAGIC_ASSERT( context, UniqueContext );
621 
622      region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
623      if (region) {
624           for (i=0; i<_UDCI_NUM; i++)
625                stret_region_get_input( region, i, x, y, &input_switch->targets[i].normal );
626      }
627      else {
628           for (i=0; i<_UDCI_NUM; i++)
629                input_switch->targets[i].normal = NULL;
630      }
631 
632      for (i=0; i<_UDCI_NUM; i++) {
633           UniqueInputTarget *target = &input_switch->targets[i];
634 
635           updated[i] = target_switch( input_switch, i,
636                                       target->fixed ? : target->implicit ? : target->normal );
637      }
638 
639      return updated[UDCI_POINTER];
640 }
641 
642 ReactionResult
_unique_input_switch_device_listener(const void * msg_data,void * ctx)643 _unique_input_switch_device_listener( const void *msg_data,
644                                       void       *ctx )
645 {
646      const UniqueInputEvent *event  = msg_data;
647      UniqueInputSwitch      *inpsw  = ctx;
648      UniqueInputTarget      *target = NULL;
649      UniqueContext          *context;
650 
651      (void) event;
652      (void) inpsw;
653 
654      D_ASSERT( event != NULL );
655 
656      D_MAGIC_ASSERT( inpsw, UniqueInputSwitch );
657 
658      context = inpsw->context;
659 
660      D_MAGIC_ASSERT( context, UniqueContext );
661 
662      if (dfb_windowstack_lock( context->stack ))
663           return RS_OK;
664 
665      if (!context->active) {
666           dfb_windowstack_unlock( context->stack );
667           return RS_OK;
668      }
669 
670      D_DEBUG_AT( UniQuE_InpSw, "_unique_input_switch_device_listener( %p, %p )\n",
671                  event, inpsw );
672 
673      switch (event->type) {
674           case UIET_MOTION:
675                target = &inpsw->targets[UDCI_POINTER];
676 
677                inpsw->x = event->pointer.x;
678                inpsw->y = event->pointer.y;
679 
680                if (!target->fixed && !target->implicit && update_targets( inpsw ))
681                     break;
682 
683                target_dispatch( target, event );
684                break;
685 
686           case UIET_BUTTON:
687                target = &inpsw->targets[UDCI_POINTER];
688 
689                if (event->pointer.press && !target->implicit) {
690                     D_DEBUG_AT( UniQuE_InpSw, "  -> implicit pointer grab, %p\n", target->current );
691 
692                     target->implicit = target->current;
693                }
694 
695                target_dispatch( target, event );
696 
697                if (!event->pointer.press && !event->pointer.buttons) {
698                     D_ASSUME( target->implicit != NULL );
699 
700                     if (target->implicit) {
701                          D_DEBUG_AT( UniQuE_InpSw, "  -> implicit pointer ungrab, %p\n", target->implicit );
702 
703                          target->implicit = NULL;
704 
705                          if (!target->fixed)
706                               update_targets( inpsw );
707                     }
708                }
709                break;
710 
711           case UIET_WHEEL:
712                target_dispatch( &inpsw->targets[UDCI_WHEEL], event );
713                break;
714 
715           case UIET_KEY:
716                target = &inpsw->targets[UDCI_KEYBOARD];
717 
718                if (event->keyboard.press && !target->implicit) {
719                     D_DEBUG_AT( UniQuE_InpSw, "  -> implicit keyboard grab, %p\n", target->current );
720 
721                     target->implicit = target->current;
722                }
723 
724                target_dispatch( target, event );
725 
726                if (!event->keyboard.press && !event->keyboard.modifiers) {
727                     //D_ASSUME( target->implicit != NULL );
728 
729                     if (target->implicit) {
730                          D_DEBUG_AT( UniQuE_InpSw, "  -> implicit keyboard ungrab, %p\n", target->implicit );
731 
732                          if (!target->fixed)
733                               target_switch( inpsw, UDCI_KEYBOARD, target->normal );
734 
735                          target->implicit = NULL;
736                     }
737                }
738                break;
739 
740           default:
741                D_ONCE( "unknown event type" );
742                break;
743      }
744 
745      dfb_windowstack_unlock( context->stack );
746 
747      return RS_OK;
748 }
749 
750 /**************************************************************************************************/
751 
752 static void
purge_connection(UniqueInputSwitch * input_switch,SwitchConnection * connection)753 purge_connection( UniqueInputSwitch *input_switch,
754                   SwitchConnection  *connection )
755 {
756      UniqueContext *context;
757 
758      D_DEBUG_AT( UniQuE_InpSw, "purge_connection( %p, %p )\n", input_switch, connection );
759 
760      D_MAGIC_ASSERT( input_switch, UniqueInputSwitch );
761      D_MAGIC_ASSERT( connection, SwitchConnection );
762 
763      context = input_switch->context;
764 
765      D_MAGIC_ASSERT( context, UniqueContext );
766 
767      /* Detach global reaction for receiving events. */
768      unique_device_detach_global( connection->device, &connection->reaction );
769 
770      direct_list_remove( &input_switch->connections, &connection->link );
771 
772      D_MAGIC_CLEAR( connection );
773 
774      SHFREE( context->shmpool, connection );
775 }
776 
777