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/object.h>
38 #include <fusion/shmalloc.h>
39 
40 #include <core/coretypes.h>
41 #include <core/input.h>
42 #include <core/layer_context.h>
43 #include <core/layer_region.h>
44 #include <core/layers.h>
45 #include <core/layers_internal.h>      /* FIXME */
46 #include <core/state.h>
47 #include <core/surface.h>
48 #include <core/windowstack.h>
49 #include <core/windows_internal.h>     /* FIXME */
50 
51 #include <gfx/util.h>
52 
53 #include <misc/conf.h>
54 #include <misc/util.h>
55 
56 #include <unique/context.h>
57 #include <unique/device.h>
58 #include <unique/input_channel.h>
59 #include <unique/input_switch.h>
60 #include <unique/internal.h>
61 
62 
63 D_DEBUG_DOMAIN( UniQuE_Context, "UniQuE/Context", "UniQuE's Stack Context" );
64 
65 
66 static const ReactionFunc unique_context_globals[] = {
67      _unique_wm_module_context_listener,
68      NULL
69 };
70 
71 /**************************************************************************************************/
72 
73 static void
context_destructor(FusionObject * object,bool zombie,void * ctx)74 context_destructor( FusionObject *object, bool zombie, void *ctx )
75 {
76      int            i;
77      UniqueContext *context = (UniqueContext*) object;
78 
79      D_DEBUG_AT( UniQuE_Context, "destroying %p (stack %p)%s\n",
80                  context, context->stack, zombie ? " (ZOMBIE)" : "");
81 
82      D_ASSUME( fusion_vector_is_empty( &context->windows ) );
83 
84      unique_context_notify( context, UCNF_DESTROYED );
85 
86      unique_device_detach_global( context->devices[UDCI_POINTER], &context->cursor_reaction );
87 
88 
89      unique_input_switch_drop( context->input_switch, context->foo_channel );
90 
91      unique_input_channel_destroy( context->foo_channel );
92 
93      unique_input_switch_destroy( context->input_switch );
94 
95 
96      for (i=0; i<_UDCI_NUM; i++)
97           unique_device_destroy( context->devices[i] );
98 
99 
100      while (fusion_vector_has_elements( &context->windows )) {
101           unique_window_destroy( fusion_vector_at( &context->windows, 0 ) );
102      }
103 
104      stret_region_destroy( context->root );
105 
106 
107      fusion_vector_destroy( &context->windows );
108 
109      dfb_surface_unlink( &context->surface );
110 
111      dfb_layer_region_unlink( &context->region );
112 
113      D_MAGIC_CLEAR( context );
114 
115      fusion_object_destroy( object );
116 }
117 
118 FusionObjectPool *
unique_context_pool_create(const FusionWorld * world)119 unique_context_pool_create( const FusionWorld *world )
120 {
121      return fusion_object_pool_create( "UniQuE Context Pool", sizeof(UniqueContext),
122                                        sizeof(UniqueContextNotification), context_destructor, NULL, world );
123 }
124 
125 /**************************************************************************************************/
126 
127 static DFBEnumerationResult
connect_device(CoreInputDevice * source,void * ctx)128 connect_device( CoreInputDevice *source,
129                 void            *ctx )
130 {
131      UniqueDevice *device = ctx;
132 
133      D_MAGIC_ASSERT( device, UniqueDevice );
134 
135      unique_device_connect( device, source );
136 
137      return DFENUM_OK;
138 }
139 
140 static DFBResult
create_devices(CoreDFB * core,UniqueContext * context,WMShared * shared)141 create_devices( CoreDFB       *core,
142                 UniqueContext *context,
143                 WMShared      *shared )
144 {
145      int       i;
146      DFBResult ret;
147 
148      D_MAGIC_ASSERT( context, UniqueContext );
149      D_MAGIC_ASSERT( shared, WMShared );
150 
151      for (i=0; i<_UDCI_NUM; i++) {
152           DFBInputDeviceCapabilities caps;
153 
154           ret = unique_device_create( core, context, shared->device_classes[i],
155                                       context, &context->devices[i] );
156           if (ret)
157                goto error;
158 
159           ret = unique_input_switch_add( context->input_switch, context->devices[i] );
160           if (ret)
161                goto error_add;
162 
163           switch (i) {
164                case UDCI_POINTER:
165                     caps = DICAPS_AXES | DICAPS_BUTTONS;
166                     break;
167 
168                case UDCI_WHEEL:
169                     caps = DICAPS_AXES;
170                     break;
171 
172                case UDCI_KEYBOARD:
173                     caps = DICAPS_KEYS;
174                     break;
175 
176                default:
177                     caps = DICAPS_ALL;
178                     break;
179           }
180 
181           dfb_input_enumerate_devices( connect_device, context->devices[i], caps );
182      }
183 
184      return DFB_OK;
185 
186 
187 error_add:
188      unique_device_destroy( context->devices[i] );
189 
190 error:
191      while (--i >= 0)
192           unique_device_destroy( context->devices[i] );
193 
194      return ret;
195 }
196 
197 /**************************************************************************************************/
198 
199 DFBResult
unique_context_create(CoreDFB * core,CoreWindowStack * stack,CoreLayerRegion * region,DFBDisplayLayerID layer_id,WMShared * shared,UniqueContext ** ret_context)200 unique_context_create( CoreDFB            *core,
201                        CoreWindowStack    *stack,
202                        CoreLayerRegion    *region,
203                        DFBDisplayLayerID   layer_id,
204                        WMShared           *shared,
205                        UniqueContext     **ret_context )
206 {
207      int            i;
208      DFBResult      ret;
209      UniqueContext *context;
210 
211      D_ASSERT( stack != NULL );
212      D_MAGIC_ASSERT( shared, WMShared );
213      D_ASSERT( ret_context != NULL );
214 
215      context = unique_wm_create_context();
216      if (!context)
217           return DFB_FUSION;
218 
219      context->stack    = stack;
220      context->shared   = shared;
221      context->layer_id = layer_id;
222      context->color    = (DFBColor) { 0xff, 0xa0, 0xd0, 0xf0 };
223      context->shmpool  = stack->shmpool;
224 
225      fusion_vector_init( &context->windows, 16, context->shmpool );
226 
227      /* Create Root Region. */
228      ret = stret_region_create( shared->region_classes[URCI_ROOT], context, 0,
229                                 SRF_ACTIVE | SRF_OUTPUT, _UNRL_NUM,
230                                 0, 0, INT_MAX, INT_MAX,
231                                 NULL, 0, context->shmpool, &context->root );
232      if (ret)
233           goto error;
234 
235      /* Link layer region. */
236      ret = dfb_layer_region_link( &context->region, region );
237      if (ret)
238           goto error;
239 
240      /* Get the region's surface. */
241      ret = dfb_layer_region_get_surface( region, &context->surface );
242      if (ret)
243           goto error;
244 
245      /* Make it global. */
246      ret = dfb_surface_globalize( context->surface );
247      if (ret) {
248           dfb_surface_unref( context->surface );
249           goto error;
250      }
251 
252      D_MAGIC_SET( context, UniqueContext );
253 
254      ret = unique_input_switch_create( context, &context->input_switch );
255      if (ret)
256           goto error_switch;
257 
258      ret = create_devices( core, context, shared );
259      if (ret)
260           goto error_devices;
261 
262      ret = unique_input_channel_create( core, context, &context->foo_channel );
263      if (ret)
264           goto error_foo_channel;
265 
266      ret = unique_device_attach_global( context->devices[UDCI_POINTER],
267                                         UNIQUE_CURSOR_DEVICE_LISTENER,
268                                         context, &context->cursor_reaction );
269      if (ret)
270           goto error_attach_cursor;
271 
272      /* Change global reaction lock. */
273      fusion_object_set_lock( &context->object, &context->stack->context->lock );
274 
275      /* Activate Object. */
276      fusion_object_activate( &context->object );
277 
278      /* Return new context. */
279      *ret_context = context;
280 
281      return DFB_OK;
282 
283 
284 error_attach_cursor:
285      unique_input_channel_destroy( context->foo_channel );
286 
287 error_foo_channel:
288      for (i=0; i<_UDCI_NUM; i++)
289           unique_device_destroy( context->devices[i] );
290 
291 error_devices:
292      unique_input_switch_destroy( context->input_switch );
293 
294 error_switch:
295      D_MAGIC_CLEAR( context );
296 
297      dfb_surface_unlink( &context->surface );
298 
299 error:
300      if (context->region)
301           dfb_layer_region_unlink( &context->region );
302 
303      if (context->root)
304           stret_region_destroy( context->root );
305 
306      fusion_vector_destroy( &context->windows );
307 
308      fusion_object_destroy( &context->object );
309 
310      return ret;
311 }
312 
313 DFBResult
unique_context_notify(UniqueContext * context,UniqueContextNotificationFlags flags)314 unique_context_notify( UniqueContext                  *context,
315                        UniqueContextNotificationFlags  flags )
316 {
317      UniqueContextNotification notification;
318 
319      D_MAGIC_ASSERT( context, UniqueContext );
320 
321      D_ASSERT( flags != UCNF_NONE );
322 
323      D_ASSERT( ! (flags & ~UCNF_ALL) );
324 
325      notification.flags   = flags;
326      notification.context = context;
327 
328      return unique_context_dispatch( context, &notification, unique_context_globals );
329 }
330 
331 DFBResult
unique_context_set_active(UniqueContext * context,bool active)332 unique_context_set_active( UniqueContext  *context,
333                            bool            active )
334 {
335      D_MAGIC_ASSERT( context, UniqueContext );
336 
337      D_ASSUME( context->active != active );
338 
339      if (context->active == active)
340           return DFB_OK;
341 
342      context->active = active;
343 
344      if (active)
345           return dfb_windowstack_repaint_all( context->stack );
346 
347      /* Force release of all pressed keys. */
348      return unique_context_flush_keys( context );
349 }
350 
351 DFBResult
unique_context_set_color(UniqueContext * context,const DFBColor * color)352 unique_context_set_color( UniqueContext  *context,
353                           const DFBColor *color )
354 {
355      D_MAGIC_ASSERT( context, UniqueContext );
356 
357      D_ASSERT( color != NULL );
358 
359      context->color = *color;
360 
361      return dfb_windowstack_repaint_all( context->stack );
362 }
363 
364 /* HACK: dumped in here for now, will move into cursor class */
365 void
unique_draw_cursor(CoreWindowStack * stack,UniqueContext * context,CardState * state,DFBRegion * region)366 unique_draw_cursor( CoreWindowStack *stack, UniqueContext *context, CardState *state, DFBRegion *region )
367 {
368      DFBRectangle            src;
369      DFBSurfaceBlittingFlags flags = DSBLIT_BLEND_ALPHACHANNEL;
370 
371      D_ASSERT( stack != NULL );
372      D_MAGIC_ASSERT( context, UniqueContext );
373      D_MAGIC_ASSERT( state, CardState );
374      DFB_REGION_ASSERT( region );
375 
376      D_ASSUME( stack->cursor.opacity > 0 );
377 
378      /* Initialize source rectangle. */
379      src.x = region->x1 - stack->cursor.x + stack->cursor.hot.x;
380      src.y = region->y1 - stack->cursor.y + stack->cursor.hot.y;
381      src.w = region->x2 - region->x1 + 1;
382      src.h = region->y2 - region->y1 + 1;
383 
384      /* Use global alpha blending. */
385      if (stack->cursor.opacity != 0xFF) {
386           flags |= DSBLIT_BLEND_COLORALPHA;
387 
388           /* Set opacity as blending factor. */
389           if (state->color.a != stack->cursor.opacity) {
390                state->color.a   = stack->cursor.opacity;
391                state->modified |= SMF_COLOR;
392           }
393      }
394 
395      /* Different compositing methods depending on destination format. */
396      if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
397           if (DFB_PIXELFORMAT_HAS_ALPHA( state->destination->config.format )) {
398                /*
399                 * Always use compliant Porter/Duff SRC_OVER,
400                 * if the destination has an alpha channel.
401                 *
402                 * Cd = destination color  (non-premultiplied)
403                 * Ad = destination alpha
404                 *
405                 * Cs = source color       (non-premultiplied)
406                 * As = source alpha
407                 *
408                 * Ac = color alpha
409                 *
410                 * cd = Cd * Ad            (premultiply destination)
411                 * cs = Cs * As            (premultiply source)
412                 *
413                 * The full equation to calculate resulting color and alpha (premultiplied):
414                 *
415                 * cx = cd * (1-As*Ac) + cs * Ac
416                 * ax = Ad * (1-As*Ac) + As * Ac
417                 */
418                dfb_state_set_src_blend( state, DSBF_ONE );
419 
420                /* Need to premultiply source with As*Ac or only with Ac? */
421                if (! (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED))
422                     flags |= DSBLIT_SRC_PREMULTIPLY;
423                else if (flags & DSBLIT_BLEND_COLORALPHA)
424                     flags |= DSBLIT_SRC_PREMULTCOLOR;
425 
426                /* Need to premultiply/demultiply destination? */
427 //               if (! (state->destination->caps & DSCAPS_PREMULTIPLIED))
428 //                    flags |= DSBLIT_DST_PREMULTIPLY | DSBLIT_DEMULTIPLY;
429           }
430           else {
431                /*
432                 * We can avoid DSBLIT_SRC_PREMULTIPLY for destinations without an alpha channel
433                 * by using another blending function, which is more likely that it's accelerated
434                 * than premultiplication at this point in time.
435                 *
436                 * This way the resulting alpha (ax) doesn't comply with SRC_OVER,
437                 * but as the destination doesn't have an alpha channel it's no problem.
438                 *
439                 * As the destination's alpha value is always 1.0 there's no need for
440                 * premultiplication. The resulting alpha value will also be 1.0 without
441                 * exceptions, therefore no need for demultiplication.
442                 *
443                 * cx = Cd * (1-As*Ac) + Cs*As * Ac  (still same effect as above)
444                 * ax = Ad * (1-As*Ac) + As*As * Ac  (wrong, but discarded anyways)
445                 */
446                if (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED) {
447                     /* Need to premultiply source with Ac? */
448                     if (flags & DSBLIT_BLEND_COLORALPHA)
449                          flags |= DSBLIT_SRC_PREMULTCOLOR;
450 
451                     dfb_state_set_src_blend( state, DSBF_ONE );
452                }
453                else
454                     dfb_state_set_src_blend( state, DSBF_SRCALPHA );
455           }
456      }
457 
458      /* Set blitting flags. */
459      dfb_state_set_blitting_flags( state, flags );
460 
461      /* Set blitting source. */
462      state->source    = stack->cursor.surface;
463      state->modified |= SMF_SOURCE;
464 
465      /* Blit from the window to the region being updated. */
466      dfb_gfxcard_blit( &src, region->x1, region->y1, state );
467 
468      /* Reset blitting source. */
469      state->source    = NULL;
470      state->modified |= SMF_SOURCE;
471 }
472 
473 DFBResult
unique_context_update(UniqueContext * context,const DFBRegion * updates,int num,DFBSurfaceFlipFlags flags)474 unique_context_update( UniqueContext       *context,
475                        const DFBRegion     *updates,
476                        int                  num,
477                        DFBSurfaceFlipFlags  flags )
478 {
479      int        i;
480      CoreLayer *layer;
481      CardState *state;
482      int        count = 0;
483      DFBRegion  root;
484      DFBRegion  regions[num];
485      DFBRegion  cursor_inter;
486 
487      D_MAGIC_ASSERT( context, UniqueContext );
488      D_ASSERT( context->stack != NULL );
489 
490      D_ASSERT( updates != NULL );
491      D_ASSERT( num > 0 );
492 
493      if (!context->active)
494           return DFB_OK;
495 
496      D_DEBUG_AT( UniQuE_Context, "unique_context_update( num %d, flags 0x%08x )\n", num, flags );
497 
498      layer = dfb_layer_at( context->layer_id );
499      state = dfb_layer_state( layer );
500 
501      root = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, context->width, context->height );
502 
503      for (i=0; i<num; i++) {
504           const DFBRegion *region = &updates[i];
505 
506           if (!dfb_region_region_intersects( region, &root ))
507                continue;
508 
509           regions[count++] = DFB_REGION_INIT_INTERSECTED( region, 0, 0, root.x2, root.y2 );
510 
511           D_DEBUG_AT( UniQuE_Context, "    (%2d) %4d, %4d - %4dx%4d\n", i,
512                       DFB_RECTANGLE_VALS_FROM_REGION( &regions[count-1] ) );
513      }
514 
515      if (!count) {
516           D_DEBUG_AT( UniQuE_Context, "    -> No intersection with root!\n" );
517           return DFB_OK;
518      }
519 
520      /* Set destination. */
521      state->destination  = context->surface;
522      state->modified    |= SMF_DESTINATION;
523 
524      for (i=0; i<count; i++) {
525           const DFBRegion *update = &regions[i];
526 
527           /* Set clipping region. */
528           dfb_state_set_clip( state, update );
529 
530           /* Compose updated region. */
531           stret_region_update( context->root, update, state );
532 
533           /* Update cursor? */
534           cursor_inter = context->cursor_region;
535           if (context->cursor_drawn && dfb_region_region_intersect( &cursor_inter, update )) {
536                DFBRectangle rect = DFB_RECTANGLE_INIT_FROM_REGION( &cursor_inter );
537 
538                D_ASSUME( context->cursor_bs_valid );
539 
540                dfb_gfx_copy_to( context->surface, context->cursor_bs, &rect,
541                                 rect.x - context->cursor_region.x1,
542                                 rect.y - context->cursor_region.y1, true );
543 
544                unique_draw_cursor( context->stack, context, state, &cursor_inter );
545           }
546      }
547 
548      /* Reset destination. */
549      state->destination  = NULL;
550      state->modified    |= SMF_DESTINATION;
551 
552      /* Software cursor code relies on a valid back buffer. */
553      if (context->stack->cursor.enabled)
554           flags |= DSFLIP_BLIT;
555 
556      /* Flip all updated regions. */
557      for (i=0; i<count; i++) {
558           const DFBRegion *update = &regions[i];
559 
560           dfb_layer_region_flip_update( context->region, update, flags );
561      }
562 
563      return DFB_OK;
564 }
565 
566 DFBResult
unique_context_resize(UniqueContext * context,int width,int height)567 unique_context_resize( UniqueContext *context,
568                        int            width,
569                        int            height )
570 {
571      D_MAGIC_ASSERT( context, UniqueContext );
572 
573      context->width  = width;
574      context->height = height;
575 
576      stret_region_resize( context->root, width, height );
577 
578      return DFB_OK;
579 }
580 
581 DFBResult
unique_context_flush_keys(UniqueContext * context)582 unique_context_flush_keys( UniqueContext *context )
583 {
584      D_MAGIC_ASSERT( context, UniqueContext );
585 
586      return DFB_OK;
587 }
588 
589 DFBResult
unique_context_window_at(UniqueContext * context,int x,int y,UniqueWindow ** ret_window)590 unique_context_window_at( UniqueContext  *context,
591                           int             x,
592                           int             y,
593                           UniqueWindow  **ret_window )
594 {
595      int              i;
596      CoreWindowStack *stack;
597      WMShared        *shared;
598      UniqueWindow    *window = NULL;
599 
600      D_MAGIC_ASSERT( context, UniqueContext );
601 
602      D_ASSERT( ret_window != NULL );
603 
604      stack = context->stack;
605      shared = context->shared;
606 
607      D_ASSERT( stack != NULL );
608      D_MAGIC_ASSERT( shared, WMShared );
609 
610      if (stack->cursor.enabled) {
611           StretRegion *region;
612 
613           if (x < 0)
614                x = stack->cursor.x;
615           if (y < 0)
616                y = stack->cursor.y;
617 
618           region = stret_region_at( context->root, x, y, SRF_INPUT, SRCID_UNKNOWN );
619           if (region && (region->clazz == shared->region_classes[URCI_FOO] ||
620                          region->clazz == shared->region_classes[URCI_WINDOW]))
621           {
622                window = stret_region_data( region );
623 
624                D_MAGIC_ASSERT( window, UniqueWindow );
625           }
626      }
627      else {
628           fusion_vector_foreach_reverse (window, i, context->windows)
629                if (window->opacity && !(window->options & DWOP_GHOST))
630                     break;
631 
632           if (i < 0)
633                window = NULL;
634      }
635 
636      D_MAGIC_ASSERT_IF( window, UniqueWindow );
637 
638      *ret_window = window;
639 
640      return DFB_OK;
641 }
642 
643 DFBResult
unique_context_lookup_window(UniqueContext * context,DFBWindowID window_id,UniqueWindow ** ret_window)644 unique_context_lookup_window( UniqueContext  *context,
645                               DFBWindowID     window_id,
646                               UniqueWindow  **ret_window )
647 {
648      int           i;
649      UniqueWindow *window = NULL;
650 
651      D_ASSERT( ret_window != NULL );
652 
653      D_MAGIC_ASSERT( context, UniqueContext );
654 
655      fusion_vector_foreach_reverse (window, i, context->windows) {
656           if (window->window->id == window_id)
657                break;
658      }
659 
660      *ret_window = window;
661 
662      return DFB_OK;
663 }
664 
665 DFBResult
unique_context_enum_windows(UniqueContext * context,CoreWMWindowCallback callback,void * callback_ctx)666 unique_context_enum_windows( UniqueContext        *context,
667                              CoreWMWindowCallback  callback,
668                              void                 *callback_ctx )
669 {
670      int           i;
671      UniqueWindow *window = NULL;
672 
673      D_ASSERT( callback != NULL );
674 
675      D_MAGIC_ASSERT( context, UniqueContext );
676 
677      fusion_vector_foreach_reverse (window, i, context->windows) {
678           if (callback( window->window, callback_ctx ) != DFENUM_OK)
679                break;
680      }
681 
682      return DFB_OK;
683 }
684 
685 /**************************************************************************************************/
686 
687 ReactionResult
_unique_cursor_device_listener(const void * msg_data,void * ctx)688 _unique_cursor_device_listener( const void *msg_data,
689                                 void       *ctx )
690 {
691      const UniqueInputEvent *event   = msg_data;
692      UniqueContext          *context = ctx;
693 
694      D_ASSERT( event != NULL );
695 
696      D_MAGIC_ASSERT( context, UniqueContext );
697 
698      D_DEBUG_AT( UniQuE_Context, "_unique_cursor_device_listener( %p, %p )\n", event, context );
699 
700      switch (event->type) {
701           case UIET_MOTION:
702                dfb_windowstack_cursor_warp( context->stack, event->pointer.x, event->pointer.y );
703                break;
704 
705           default:
706                break;
707      }
708 
709      return RS_OK;
710 }
711 
712