1 /*
2    (c) Copyright 2001-2010  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 <string.h>
32 
33 #include <directfb.h>
34 
35 #include <direct/debug.h>
36 #include <direct/list.h>
37 #include <direct/mem.h>
38 #include <direct/messages.h>
39 
40 #include <fusion/reactor.h>
41 #include <fusion/shmalloc.h>
42 
43 #include <core/CoreWindowStack.h>
44 
45 #include <core/core.h>
46 #include <core/input.h>
47 #include <core/layer_context.h>
48 #include <core/layers_internal.h>
49 #include <core/surface.h>
50 #include <core/windows_internal.h>
51 #include <core/windowstack.h>
52 #include <core/wm.h>
53 
54 #include <misc/conf.h>
55 
56 #include <gfx/convert.h>
57 #include <gfx/util.h>
58 
59 
60 #define CURSORFILE  DATADIR"/cursor.dat"
61 
62 
63 D_DEBUG_DOMAIN( Core_WindowStack, "Core/WindowStack", "DirectFB Core WindowStack" );
64 
65 /**********************************************************************************************************************/
66 
67 typedef struct {
68      DirectLink       link;
69 
70      DFBInputDeviceID id;
71      GlobalReaction   reaction;
72 } StackDevice;
73 
74 typedef struct {
75      DirectLink                  link;
76 
77      DFBInputDeviceKeySymbol     symbol;
78      DFBInputDeviceModifierMask  modifiers;
79 
80      CoreWindow                 *owner;
81 } GrabbedKey;
82 
83 typedef struct {
84      DirectLink                  link;
85      void                       *ctx;
86 } Stack_Container;
87 
88 static  DirectLink      *stack_containers = NULL;
89 static  pthread_mutex_t  stack_containers_lock = PTHREAD_MUTEX_INITIALIZER;
90 
91 /**********************************************************************************************************************/
92 
93 static DFBResult load_default_cursor  ( CoreDFB         *core,
94                                         CoreWindowStack *stack );
95 static DFBResult create_cursor_surface( CoreWindowStack *stack,
96                                         int              width,
97                                         int              height );
98 
99 /**********************************************************************************************************************/
100 
101 static DFBEnumerationResult stack_attach_devices( CoreInputDevice *device,
102                                                   void            *ctx );
103 
104 static DFBEnumerationResult stack_detach_devices( CoreInputDevice *device,
105                                                   void            *ctx );
106 
107 /**********************************************************************************************************************/
108 
109 // Implement stack_containers_XXX function family to maintain the connections
110 // between windowstacks and input devices.
111 static void
stack_containers_add(CoreWindowStack * p)112 stack_containers_add(CoreWindowStack *p)
113 {
114      Stack_Container    *stack_cntr;
115 
116      D_DEBUG_AT( Core_WindowStack, "Enter:%s()\n", __FUNCTION__);
117 
118      pthread_mutex_lock( &stack_containers_lock );
119 
120      stack_cntr = (Stack_Container *) D_CALLOC(1, sizeof(Stack_Container));
121      if (stack_cntr != NULL) {
122           stack_cntr->ctx = (void *)p;
123           direct_list_append(&stack_containers, &stack_cntr->link);
124      }
125      else{
126           D_ERROR( "Core/WindowStack: stack_cntr = NULL\n");
127      }
128 
129      pthread_mutex_unlock( &stack_containers_lock );
130 }
131 
132 static void
stack_containers_remove(CoreWindowStack * p)133 stack_containers_remove(CoreWindowStack *p)
134 {
135      Stack_Container    *stack_cntr = NULL;
136 
137      D_DEBUG_AT( Core_WindowStack, "Enter:%s()\n", __FUNCTION__);
138 
139      pthread_mutex_lock( &stack_containers_lock );
140 
141      direct_list_foreach(stack_cntr, stack_containers) {
142           if((void *)p == stack_cntr->ctx) {
143                direct_list_remove(&stack_containers, &stack_cntr->link);
144                D_FREE(stack_cntr);
145           }
146      }
147 
148      pthread_mutex_unlock( &stack_containers_lock );
149 }
150 
151 void
stack_containers_attach_device(CoreInputDevice * device)152 stack_containers_attach_device(CoreInputDevice *device)
153 {
154      Stack_Container    *stack_container;
155 
156      D_DEBUG_AT( Core_WindowStack, "Enter:%s()\n", __FUNCTION__);
157 
158      pthread_mutex_lock( &stack_containers_lock );
159 
160      direct_list_foreach(stack_container, stack_containers) {
161           stack_attach_devices(device, stack_container->ctx);
162      }
163 
164      pthread_mutex_unlock( &stack_containers_lock );
165 }
166 
167 void
stack_containers_detach_device(CoreInputDevice * device)168 stack_containers_detach_device(CoreInputDevice *device)
169 {
170      Stack_Container    *stack_container;
171 
172      D_DEBUG_AT( Core_WindowStack, "Enter:%s()\n", __FUNCTION__);
173 
174      pthread_mutex_lock( &stack_containers_lock );
175 
176      direct_list_foreach(stack_container, stack_containers) {
177           stack_detach_devices(device, stack_container->ctx);
178      }
179 
180      pthread_mutex_unlock( &stack_containers_lock );
181 }
182 
183 /*
184  * Allocates and initializes a window stack.
185  */
186 CoreWindowStack*
dfb_windowstack_create(CoreLayerContext * context)187 dfb_windowstack_create( CoreLayerContext *context )
188 {
189      DFBResult          ret;
190      CoreWindowStack   *stack;
191      CoreLayer         *layer;
192      CoreSurfacePolicy  policy = CSP_SYSTEMONLY;
193 
194      D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, context );
195 
196      D_ASSERT( context != NULL );
197 
198      layer = dfb_layer_at( context->layer_id );
199 
200      /* Allocate window stack data (completely shared) */
201      stack = (CoreWindowStack*) SHCALLOC( context->shmpool, 1, sizeof(CoreWindowStack) );
202      if (!stack) {
203           D_OOSHM();
204           return NULL;
205      }
206 
207      stack->shmpool = context->shmpool;
208 
209      /* Store context which we belong to. */
210      stack->context = context;
211 
212      /* Set default acceleration */
213      stack->cursor.numerator   = 2;
214      stack->cursor.denominator = 1;
215      stack->cursor.threshold   = 4;
216 
217      /* Choose cursor surface policy. */
218      if (context->config.buffermode != DLBM_BACKSYSTEM) {
219           CardCapabilities card_caps;
220 
221           /* Use the explicitly specified policy? */
222           if (dfb_config->window_policy != -1)
223                policy = dfb_config->window_policy;
224           else {
225                /* Examine the hardware capabilities. */
226                dfb_gfxcard_get_capabilities( &card_caps );
227 
228                if (card_caps.accel & DFXL_BLIT && card_caps.blitting & DSBLIT_BLEND_ALPHACHANNEL)
229                     policy = CSP_VIDEOHIGH;
230           }
231      }
232 
233      stack->cursor.policy = policy;
234 
235      /* Set default background mode. */
236      stack->bg.mode        = DLBM_DONTCARE;
237      stack->bg.color_index = -1;
238 
239      D_MAGIC_SET( stack, CoreWindowStack );
240 
241      /* Initialize window manager */
242      ret = dfb_wm_init_stack( stack );
243      if (ret) {
244           D_MAGIC_CLEAR( stack );
245           SHFREE( context->shmpool, stack );
246           return NULL;
247      }
248 
249      /* Attach to all input devices */
250      dfb_input_enumerate_devices( stack_attach_devices, stack, DICAPS_ALL );
251 
252      stack_containers_add(stack);
253 
254      CoreWindowStack_Init_Dispatch( layer->core, stack, &stack->call );
255 
256      D_DEBUG_AT( Core_WindowStack, "  -> %p\n", stack );
257 
258      return stack;
259 }
260 
261 void
dfb_windowstack_detach_devices(CoreWindowStack * stack)262 dfb_windowstack_detach_devices( CoreWindowStack *stack )
263 {
264      DirectLink *l;
265 
266      D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack );
267 
268      D_MAGIC_ASSERT( stack, CoreWindowStack );
269 
270      stack_containers_remove(stack);
271 
272      /* Detach all input devices. */
273      l = stack->devices;
274      while (l) {
275           DirectLink  *next   = l->next;
276           StackDevice *device = (StackDevice*) l;
277 
278           dfb_input_detach_global( dfb_input_device_at( device->id ),
279                                    &device->reaction );
280 
281           SHFREE( stack->shmpool, device );
282 
283           l = next;
284      }
285 }
286 
287 void
dfb_windowstack_destroy(CoreWindowStack * stack)288 dfb_windowstack_destroy( CoreWindowStack *stack )
289 {
290      D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack );
291 
292      D_MAGIC_ASSERT( stack, CoreWindowStack );
293 
294      /* Unlink cursor surface. */
295      if (stack->cursor.surface)
296           dfb_surface_unlink( &stack->cursor.surface );
297 
298      /* Shutdown window manager? */
299      if (stack->flags & CWSF_INITIALIZED)
300           dfb_wm_close_stack( stack );
301 
302      /* detach listener from background surface and unlink it */
303      if (stack->bg.image) {
304           dfb_surface_detach_global( stack->bg.image,
305                                      &stack->bg.image_reaction );
306 
307           dfb_surface_unlink( &stack->bg.image );
308      }
309 
310      CoreWindowStack_Deinit_Dispatch( &stack->call );
311 
312      /* Deallocate shared stack data. */
313      if (stack->stack_data) {
314           SHFREE( stack->shmpool, stack->stack_data );
315           stack->stack_data = NULL;
316      }
317 
318      D_MAGIC_CLEAR( stack );
319 
320      /* Free stack data. */
321      SHFREE( stack->shmpool, stack );
322 }
323 
324 void
dfb_windowstack_resize(CoreWindowStack * stack,int width,int height,int rotation)325 dfb_windowstack_resize( CoreWindowStack *stack,
326                         int              width,
327                         int              height,
328                         int              rotation )
329 {
330      D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d, %d )\n", __FUNCTION__, stack, width, height, rotation );
331 
332      D_MAGIC_ASSERT( stack, CoreWindowStack );
333 
334      /* Lock the window stack. */
335      if (dfb_windowstack_lock( stack ))
336           return;
337 
338      /* Store the width and height of the stack */
339      stack->width    = width;
340      stack->height   = height;
341      stack->rotation = rotation;
342 
343      switch (stack->rotation) {
344           default:
345                D_BUG( "invalid rotation %d", stack->rotation );
346           case 0:
347                stack->rotated_blit   = DSBLIT_NOFX;
348                stack->rotated_width  = stack->width;
349                stack->rotated_height = stack->height;
350                break;
351 
352           case 90:
353                stack->rotated_blit   = DSBLIT_ROTATE90;
354                stack->rotated_width  = stack->height;
355                stack->rotated_height = stack->width;
356                break;
357 
358           case 180:
359                stack->rotated_blit   = DSBLIT_ROTATE180;
360                stack->rotated_width  = stack->width;
361                stack->rotated_height = stack->height;
362                break;
363 
364           case 270:
365                stack->rotated_blit   = DSBLIT_ROTATE270;
366                stack->rotated_width  = stack->height;
367                stack->rotated_height = stack->width;
368                break;
369      }
370 
371      /* Setup new cursor clipping region */
372      stack->cursor.region.x1 = 0;
373      stack->cursor.region.y1 = 0;
374      stack->cursor.region.x2 = width - 1;
375      stack->cursor.region.y2 = height - 1;
376 
377      /* Notify the window manager. */
378      dfb_wm_resize_stack( stack, width, height );
379 
380      /* Unlock the window stack. */
381      dfb_windowstack_unlock( stack );
382 }
383 
384 /*
385  * Prohibit access to the window stack data.
386  * Waits until stack is accessible.
387  */
388 DirectResult
dfb_windowstack_lock(CoreWindowStack * stack)389 dfb_windowstack_lock( CoreWindowStack *stack )
390 {
391      D_MAGIC_ASSERT( stack, CoreWindowStack );
392      D_ASSERT( stack->context != NULL );
393 
394      return dfb_layer_context_lock( stack->context );
395 }
396 
397 /*
398  * Allow access to the window stack data.
399  */
400 DirectResult
dfb_windowstack_unlock(CoreWindowStack * stack)401 dfb_windowstack_unlock( CoreWindowStack *stack )
402 {
403      D_MAGIC_ASSERT( stack, CoreWindowStack );
404      D_ASSERT( stack->context != NULL );
405 
406      return dfb_layer_context_unlock( stack->context );
407 }
408 
409 DFBResult
dfb_windowstack_repaint_all(CoreWindowStack * stack)410 dfb_windowstack_repaint_all( CoreWindowStack *stack )
411 {
412      DFBResult ret;
413      DFBRegion region;
414 
415      D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack );
416 
417      D_MAGIC_ASSERT( stack, CoreWindowStack );
418 
419      /* Lock the window stack. */
420      if (dfb_windowstack_lock( stack ))
421           return DFB_FUSION;
422 
423      region.x1 = 0;
424      region.y1 = 0;
425      region.x2 = stack->rotated_width  - 1;
426      region.y2 = stack->rotated_height - 1;
427 
428      ret = dfb_wm_update_stack( stack, &region, 0 );
429 
430      /* Unlock the window stack. */
431      dfb_windowstack_unlock( stack );
432 
433      return ret;
434 }
435 
436 /**********************************************************************************************************************/
437 
438 /*
439  * background handling
440  */
441 
442 DFBResult
dfb_windowstack_set_background_mode(CoreWindowStack * stack,DFBDisplayLayerBackgroundMode mode)443 dfb_windowstack_set_background_mode ( CoreWindowStack               *stack,
444                                       DFBDisplayLayerBackgroundMode  mode )
445 {
446      D_DEBUG_AT( Core_WindowStack, "%s( %p, %d )\n", __FUNCTION__, stack, mode );
447 
448      D_MAGIC_ASSERT( stack, CoreWindowStack );
449 
450      /* Lock the window stack. */
451      if (dfb_windowstack_lock( stack ))
452           return DFB_FUSION;
453 
454      /* nothing to do if mode is the same */
455      if (mode != stack->bg.mode) {
456           /* for these modes a surface is required */
457           if ((mode == DLBM_IMAGE || mode == DLBM_TILE) && !stack->bg.image) {
458                dfb_windowstack_unlock( stack );
459                return DFB_MISSINGIMAGE;
460           }
461 
462           /* set new mode */
463           stack->bg.mode = mode;
464 
465           /* force an update of the window stack */
466           if (mode != DLBM_DONTCARE)
467                dfb_windowstack_repaint_all( stack );
468      }
469 
470      /* Unlock the window stack. */
471      dfb_windowstack_unlock( stack );
472 
473      return DFB_OK;
474 }
475 
476 DFBResult
dfb_windowstack_set_background_image(CoreWindowStack * stack,CoreSurface * image)477 dfb_windowstack_set_background_image( CoreWindowStack *stack,
478                                       CoreSurface     *image )
479 {
480      D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, stack, image );
481 
482      D_MAGIC_ASSERT( stack, CoreWindowStack );
483      D_ASSERT( image != NULL );
484 
485      if (!(image->type & CSTF_SHARED))
486           return DFB_INVARG;
487 
488      /* Lock the window stack. */
489      if (dfb_windowstack_lock( stack ))
490           return DFB_FUSION;
491 
492      /* if the surface is changed */
493      if (stack->bg.image != image) {
494           /* detach listener from old surface and unlink it */
495           if (stack->bg.image) {
496                dfb_surface_detach_global( stack->bg.image,
497                                           &stack->bg.image_reaction );
498 
499                dfb_surface_unlink( &stack->bg.image );
500           }
501 
502           /* link surface object */
503           dfb_surface_link( &stack->bg.image, image );
504 
505           /* attach listener to new surface */
506           dfb_surface_attach_global( image,
507                                      DFB_WINDOWSTACK_BACKGROUND_IMAGE_LISTENER,
508                                      stack, &stack->bg.image_reaction );
509      }
510 
511      /* force an update of the window stack */
512      if (stack->bg.mode == DLBM_IMAGE || stack->bg.mode == DLBM_TILE)
513           dfb_windowstack_repaint_all( stack );
514 
515      /* Unlock the window stack. */
516      dfb_windowstack_unlock( stack );
517 
518      return DFB_OK;
519 }
520 
521 DFBResult
dfb_windowstack_set_background_color(CoreWindowStack * stack,const DFBColor * color)522 dfb_windowstack_set_background_color( CoreWindowStack *stack,
523                                       const DFBColor  *color )
524 {
525      D_ASSERT( color != NULL );
526 
527      D_DEBUG_AT( Core_WindowStack, "%s( %p, 0x%08x )\n", __FUNCTION__, stack,
528                  PIXEL_ARGB( color->a, color->r, color->g, color->b ) );
529 
530      D_MAGIC_ASSERT( stack, CoreWindowStack );
531 
532      /* Lock the window stack. */
533      if (dfb_windowstack_lock( stack ))
534           return DFB_FUSION;
535 
536      /* do nothing if color didn't change */
537      if (!DFB_COLOR_EQUAL( stack->bg.color, *color )) {
538           /* set new color */
539           stack->bg.color = *color;
540 
541           /* force an update of the window stack */
542           if (stack->bg.mode == DLBM_COLOR)
543                dfb_windowstack_repaint_all( stack );
544      }
545 
546      /* Unlock the window stack. */
547      dfb_windowstack_unlock( stack );
548 
549      return DFB_OK;
550 }
551 
552 DFBResult
dfb_windowstack_set_background_color_index(CoreWindowStack * stack,int index)553 dfb_windowstack_set_background_color_index( CoreWindowStack *stack,
554                                             int              index )
555 {
556      D_DEBUG_AT( Core_WindowStack, "%s( %p, %d )\n", __FUNCTION__, stack, index );
557 
558      D_MAGIC_ASSERT( stack, CoreWindowStack );
559 
560      /* Lock the window stack. */
561      if (dfb_windowstack_lock( stack ))
562           return DFB_FUSION;
563 
564      /* do nothing if color didn't change */
565      if (stack->bg.color_index != index) {
566           /* set new color index */
567           stack->bg.color_index = index;
568 
569           /* force an update of the window stack */
570           if (stack->bg.mode == DLBM_COLOR)
571                dfb_windowstack_repaint_all( stack );
572      }
573 
574      /* Unlock the window stack. */
575      dfb_windowstack_unlock( stack );
576 
577      return DFB_OK;
578 }
579 
580 /**********************************************************************************************************************/
581 
582 /*
583  * cursor control
584  */
585 
586 DFBResult
dfb_windowstack_cursor_enable(CoreDFB * core,CoreWindowStack * stack,bool enable)587 dfb_windowstack_cursor_enable( CoreDFB *core, CoreWindowStack *stack, bool enable )
588 {
589      DFBResult ret;
590 
591      D_DEBUG_AT( Core_WindowStack, "%s( %p, %s )\n", __FUNCTION__, stack, enable ? "enable" : "disable" );
592 
593      D_MAGIC_ASSERT( stack, CoreWindowStack );
594 
595      /* Lock the window stack. */
596      if (dfb_windowstack_lock( stack ))
597           return DFB_FUSION;
598 
599      stack->cursor.set = true;
600 
601      if (dfb_config->no_cursor || stack->cursor.enabled == enable) {
602           dfb_windowstack_unlock( stack );
603           return DFB_OK;
604      }
605 
606      if (enable && !stack->cursor.surface) {
607           ret = load_default_cursor( core, stack );
608           if (ret) {
609                dfb_windowstack_unlock( stack );
610                return ret;
611           }
612      }
613 
614      /* Keep state. */
615      stack->cursor.enabled = enable;
616 
617      /* Notify WM. */
618      dfb_wm_update_cursor( stack, enable ? CCUF_ENABLE : CCUF_DISABLE );
619 
620      /* Unlock the window stack. */
621      dfb_windowstack_unlock( stack );
622 
623      return DFB_OK;
624 }
625 
626 DFBResult
dfb_windowstack_cursor_set_opacity(CoreWindowStack * stack,u8 opacity)627 dfb_windowstack_cursor_set_opacity( CoreWindowStack *stack, u8 opacity )
628 {
629      D_DEBUG_AT( Core_WindowStack, "%s( %p, 0x%02x )\n", __FUNCTION__, stack, opacity );
630 
631      D_MAGIC_ASSERT( stack, CoreWindowStack );
632 
633      /* Lock the window stack. */
634      if (dfb_windowstack_lock( stack ))
635           return DFB_FUSION;
636 
637      if (stack->cursor.opacity != opacity) {
638           /* Set new opacity. */
639           stack->cursor.opacity = opacity;
640 
641           /* Notify WM. */
642           if (stack->cursor.enabled)
643                dfb_wm_update_cursor( stack, CCUF_OPACITY );
644      }
645 
646      /* Unlock the window stack. */
647      dfb_windowstack_unlock( stack );
648 
649      return DFB_OK;
650 }
651 
652 DFBResult
dfb_windowstack_cursor_set_shape(CoreWindowStack * stack,CoreSurface * shape,int hot_x,int hot_y)653 dfb_windowstack_cursor_set_shape( CoreWindowStack *stack,
654                                   CoreSurface     *shape,
655                                   int              hot_x,
656                                   int              hot_y )
657 {
658      DFBResult              ret;
659      CoreSurface           *cursor;
660      CoreCursorUpdateFlags  flags = CCUF_SHAPE;
661 
662      D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, hot %d, %d ) <- size %dx%d\n",
663                  __FUNCTION__, stack, shape, hot_x, hot_y,
664                  shape->config.size.w, shape->config.size.h );
665 
666      D_MAGIC_ASSERT( stack, CoreWindowStack );
667      D_ASSERT( shape != NULL );
668 
669      if (dfb_config->no_cursor)
670           return DFB_OK;
671 
672      /* Lock the window stack. */
673      if (dfb_windowstack_lock( stack ))
674           return DFB_FUSION;
675 
676      cursor = stack->cursor.surface;
677      if (!cursor) {
678           D_ASSUME( !stack->cursor.enabled );
679 
680           /* Create the a surface for the shape. */
681           ret = create_cursor_surface( stack, shape->config.size.w, shape->config.size.h );
682           if (ret) {
683                dfb_windowstack_unlock( stack );
684                return ret;
685           }
686 
687           cursor = stack->cursor.surface;
688      }
689      else if (stack->cursor.size.w != shape->config.size.w || stack->cursor.size.h != shape->config.size.h) {
690           dfb_surface_reformat( cursor, shape->config.size.w, shape->config.size.h, DSPF_ARGB );
691 
692           stack->cursor.size.w = shape->config.size.w;
693           stack->cursor.size.h = shape->config.size.h;
694 
695           /* Notify about new size. */
696           flags |= CCUF_SIZE;
697      }
698 
699      if (stack->cursor.hot.x != hot_x || stack->cursor.hot.y != hot_y) {
700           stack->cursor.hot.x = hot_x;
701           stack->cursor.hot.y = hot_y;
702 
703           /* Notify about new position. */
704           flags |= CCUF_POSITION;
705      }
706 
707      /* Copy the content of the new shape. */
708      dfb_gfx_copy( shape, cursor, NULL );
709 
710      cursor->config.caps = ((cursor->config.caps & ~DSCAPS_PREMULTIPLIED) | (shape->config.caps & DSCAPS_PREMULTIPLIED));
711 
712      /* Notify the WM. */
713      if (stack->cursor.enabled)
714           dfb_wm_update_cursor( stack, flags );
715 
716      /* Unlock the window stack. */
717      dfb_windowstack_unlock( stack );
718 
719      return DFB_OK;
720 }
721 
722 DFBResult
dfb_windowstack_cursor_warp(CoreWindowStack * stack,int x,int y)723 dfb_windowstack_cursor_warp( CoreWindowStack *stack, int x, int y )
724 {
725      D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d )\n", __FUNCTION__, stack, x, y );
726 
727      D_MAGIC_ASSERT( stack, CoreWindowStack );
728 
729      /* Lock the window stack. */
730      if (dfb_windowstack_lock( stack ))
731           return DFB_FUSION;
732 
733      if (x < 0)
734           x = 0;
735      else if (x > stack->width - 1)
736           x = stack->width - 1;
737 
738      if (y < 0)
739           y = 0;
740      else if (y > stack->height - 1)
741           y = stack->height - 1;
742 
743      if (stack->cursor.x != x || stack->cursor.y != y) {
744           stack->cursor.x = x;
745           stack->cursor.y = y;
746 
747           /* Notify the WM. */
748           if (stack->cursor.enabled)
749                dfb_wm_update_cursor( stack, CCUF_POSITION );
750      }
751 
752      /* Unlock the window stack. */
753      dfb_windowstack_unlock( stack );
754 
755      return DFB_OK;
756 }
757 
758 DFBResult
dfb_windowstack_cursor_set_acceleration(CoreWindowStack * stack,int numerator,int denominator,int threshold)759 dfb_windowstack_cursor_set_acceleration( CoreWindowStack *stack,
760                                          int              numerator,
761                                          int              denominator,
762                                          int              threshold )
763 {
764      D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d, %d )\n",
765                  __FUNCTION__, stack, numerator, denominator, threshold );
766 
767      D_MAGIC_ASSERT( stack, CoreWindowStack );
768 
769      /* Lock the window stack. */
770      if (dfb_windowstack_lock( stack ))
771           return DFB_FUSION;
772 
773      stack->cursor.numerator   = numerator;
774      stack->cursor.denominator = denominator;
775      stack->cursor.threshold   = threshold;
776 
777      /* Unlock the window stack. */
778      dfb_windowstack_unlock( stack );
779 
780      return DFB_OK;
781 }
782 
783 DFBResult
dfb_windowstack_get_cursor_position(CoreWindowStack * stack,int * ret_x,int * ret_y)784 dfb_windowstack_get_cursor_position( CoreWindowStack *stack, int *ret_x, int *ret_y )
785 {
786      D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, %p )\n", __FUNCTION__, stack, ret_x, ret_y );
787 
788      D_MAGIC_ASSERT( stack, CoreWindowStack );
789      D_ASSUME( ret_x != NULL || ret_y != NULL );
790 
791      /* Lock the window stack. */
792      if (dfb_windowstack_lock( stack ))
793           return DFB_FUSION;
794 
795      if (ret_x)
796           *ret_x = stack->cursor.x;
797 
798      if (ret_y)
799           *ret_y = stack->cursor.y;
800 
801      /* Unlock the window stack. */
802      dfb_windowstack_unlock( stack );
803 
804      return DFB_OK;
805 }
806 
807 /**********************************************************************************************************************/
808 
809 ReactionResult
_dfb_windowstack_inputdevice_listener(const void * msg_data,void * ctx)810 _dfb_windowstack_inputdevice_listener( const void *msg_data,
811                                        void       *ctx )
812 {
813      const DFBInputEvent *event = msg_data;
814      CoreWindowStack     *stack = ctx;
815 
816      D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, msg_data, ctx );
817 
818      D_ASSERT( msg_data != NULL );
819      D_MAGIC_ASSERT( stack, CoreWindowStack );
820 
821      // Dynamically add/decrease the ref to the layer context when using the
822      // layer context.  This will prevent the layer context from being
823      // destroyed when it is being used.
824 
825      int num = 0;
826 
827      // Make sure the layer context's reference count is non-zero.  If it is,
828      // return early and indicate the listener should be removed.  In this
829      // scenario, this prevents the object_reference_watcher from being called
830      // more than once triggered by the reference count changing from 1 to 0
831      // again.
832      if (dfb_layer_context_ref_stat( stack->context, &num ) || num == 0)
833           return RS_REMOVE;
834 
835      // Increase the layer context's reference count.
836      if (dfb_layer_context_ref( stack->context ))
837           return RS_REMOVE;
838 
839      /* Lock the window stack. */
840      if (dfb_windowstack_lock( stack )) {
841           dfb_layer_context_unref( stack->context );
842           return RS_REMOVE;
843      }
844 
845      /* Call the window manager to dispatch the event. */
846      if (dfb_layer_context_active( stack->context ))
847           dfb_wm_process_input( stack, event );
848 
849      /* Unlock the window stack. */
850      dfb_windowstack_unlock( stack );
851 
852      // Decrease the layer context's reference count.
853      dfb_layer_context_unref( stack->context );
854 
855      return RS_OK;
856 }
857 
858 /*
859  * listen to the background image
860  */
861 ReactionResult
_dfb_windowstack_background_image_listener(const void * msg_data,void * ctx)862 _dfb_windowstack_background_image_listener( const void *msg_data,
863                                             void       *ctx )
864 {
865      const CoreSurfaceNotification *notification = msg_data;
866      CoreWindowStack               *stack        = ctx;
867 
868      D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, msg_data, ctx );
869 
870      D_ASSERT( notification != NULL );
871      D_MAGIC_ASSERT( stack, CoreWindowStack );
872 
873      if (notification->flags & CSNF_DESTROY) {
874           if (stack->bg.image == notification->surface) {
875                D_ERROR( "Core/WindowStack: Surface for background vanished.\n" );
876 
877                stack->bg.mode  = DLBM_COLOR;
878                stack->bg.image = NULL;
879 
880                dfb_windowstack_repaint_all( stack );
881           }
882 
883           return RS_REMOVE;
884      }
885 
886      if (notification->flags & (CSNF_FLIP | CSNF_SIZEFORMAT))
887           dfb_windowstack_repaint_all( stack );
888 
889      return RS_OK;
890 }
891 
892 /**********************************************************************************************************************/
893 
894 /*
895  * internals
896  */
897 
898 static DFBEnumerationResult
stack_attach_devices(CoreInputDevice * device,void * ctx)899 stack_attach_devices( CoreInputDevice *device,
900                       void            *ctx )
901 {
902      StackDevice     *dev;
903      CoreWindowStack *stack = (CoreWindowStack*) ctx;
904 
905      D_MAGIC_ASSERT( stack, CoreWindowStack );
906 
907      dev = SHCALLOC( stack->shmpool, 1, sizeof(StackDevice) );
908      if (!dev) {
909           D_ERROR( "Core/WindowStack: Could not allocate %zu bytes\n", sizeof(StackDevice) );
910           return DFENUM_CANCEL;
911      }
912 
913      dev->id = dfb_input_device_id( device );
914 
915      direct_list_prepend( &stack->devices, &dev->link );
916 
917      dfb_input_attach_global( device, DFB_WINDOWSTACK_INPUTDEVICE_LISTENER,
918                               ctx, &dev->reaction );
919 
920      return DFENUM_OK;
921 }
922 
923 static DFBEnumerationResult
stack_detach_devices(CoreInputDevice * device,void * ctx)924 stack_detach_devices( CoreInputDevice *device,
925                         void            *ctx )
926 {
927      DirectLink *link;
928      CoreWindowStack *stack = (CoreWindowStack*) ctx;
929 
930      D_ASSERT( stack != NULL );
931      D_ASSERT( device != NULL );
932 
933      link = stack->devices;
934      while (link) {
935           DirectLink  *next   = link->next;
936           StackDevice *dev = (StackDevice*) link;
937 
938           if (dfb_input_device_id(device) == dev->id) {
939                direct_list_remove( &stack->devices, &dev->link );
940 
941                dfb_input_detach_global(device, &dev->reaction );
942                SHFREE( stack->shmpool, dev );
943                return DFENUM_OK;
944           }
945           link = next;
946      }
947      return DFENUM_CANCEL;
948 }
949 
950 /*
951  * internal function that installs the cursor window
952  * and fills it with data from 'cursor.dat'
953  */
954 static DFBResult
load_default_cursor(CoreDFB * core,CoreWindowStack * stack)955 load_default_cursor( CoreDFB *core, CoreWindowStack *stack )
956 {
957      DFBResult              ret;
958      int                    i;
959      FILE                  *f;
960      CoreSurfaceBufferLock  lock;
961      void                  *data;
962 
963      D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack );
964 
965      D_MAGIC_ASSERT( stack, CoreWindowStack );
966 
967      if (!stack->cursor.surface) {
968           ret = create_cursor_surface( stack, 40, 40 );
969           if (ret)
970                return ret;
971      }
972      else {
973           stack->cursor.hot.x  = 0;
974           stack->cursor.hot.y  = 0;
975           stack->cursor.size.w = 40;
976           stack->cursor.size.h = 40;
977      }
978 
979      /* lock the cursor surface */
980      ret = dfb_surface_lock_buffer( stack->cursor.surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
981      if (ret) {
982           D_ERROR( "Core/WindowStack: cannot lock the cursor surface!\n" );
983           return ret;
984      }
985 
986      data = lock.addr;
987 
988      /* initialize as empty cursor */
989      memset( data, 0, 40 * lock.pitch );
990 
991      /* open the file containing the cursors image data */
992      f = fopen( CURSORFILE, "rb" );
993      if (!f) {
994           ret = errno2result( errno );
995 
996           /* ignore a missing cursor file */
997           if (ret == DFB_FILENOTFOUND)
998                ret = DFB_OK;
999           else
1000                D_PERROR( "Core/WindowStack: `" CURSORFILE "` could not be opened!\n" );
1001 
1002           goto finish;
1003      }
1004 
1005      /* read from file directly into the cursor window surface */
1006      for (i=0; i<40; i++) {
1007           if (fread( data, MIN (40*4, lock.pitch), 1, f ) != 1) {
1008                ret = errno2result( errno );
1009 
1010                D_ERROR( "Core/WindowStack: unexpected end or read error of cursor data!\n" );
1011 
1012                goto finish;
1013           }
1014 #ifdef WORDS_BIGENDIAN
1015           {
1016                int i = MIN (40, lock.pitch/4);
1017                u32 *tmp_data = data;
1018 
1019                while (i--) {
1020                     *tmp_data = (*tmp_data & 0xFF000000) >> 24 |
1021                                 (*tmp_data & 0x00FF0000) >>  8 |
1022                                 (*tmp_data & 0x0000FF00) <<  8 |
1023                                 (*tmp_data & 0x000000FF) << 24;
1024                     ++tmp_data;
1025                }
1026           }
1027 #endif
1028           data += lock.pitch;
1029      }
1030 
1031 finish:
1032      if (f)
1033           fclose( f );
1034 
1035      dfb_surface_unlock_buffer( stack->cursor.surface, &lock );
1036 
1037      return ret;
1038 }
1039 
1040 static DFBResult
create_cursor_surface(CoreWindowStack * stack,int width,int height)1041 create_cursor_surface( CoreWindowStack *stack,
1042                        int              width,
1043                        int              height )
1044 {
1045      DFBResult               ret;
1046      CoreSurface            *surface;
1047      CoreLayer              *layer;
1048      CoreLayerContext       *context;
1049      DFBSurfaceCapabilities  surface_caps = DSCAPS_NONE;
1050 
1051      D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d )\n", __FUNCTION__, stack, width, height );
1052 
1053      D_MAGIC_ASSERT( stack, CoreWindowStack );
1054      D_ASSERT( stack->cursor.surface == NULL );
1055 
1056      context = stack->context;
1057 
1058      D_ASSERT( context != NULL );
1059 
1060      layer = dfb_layer_at( context->layer_id );
1061 
1062      D_ASSERT( layer != NULL );
1063 
1064      stack->cursor.x       = stack->width  / 2;
1065      stack->cursor.y       = stack->height / 2;
1066      stack->cursor.hot.x   = 0;
1067      stack->cursor.hot.y   = 0;
1068      stack->cursor.size.w  = width;
1069      stack->cursor.size.h  = height;
1070      stack->cursor.opacity = 0xFF;
1071 
1072      if (context->config.buffermode == DLBM_WINDOWS)
1073           D_WARN( "cursor not yet visible with DLBM_WINDOWS" );
1074 
1075      dfb_surface_caps_apply_policy( stack->cursor.policy, &surface_caps );
1076 
1077      /* Create the cursor surface. */
1078      ret = dfb_surface_create_simple( layer->core, width, height, DSPF_ARGB,
1079                                       surface_caps, CSTF_SHARED | CSTF_CURSOR,
1080                                       0, /* FIXME: no shared cursor objects, no cursor id */
1081                                       NULL, &surface );
1082      if (ret) {
1083           D_ERROR( "Core/WindowStack: Failed creating a surface for software cursor!\n" );
1084           return ret;
1085      }
1086 
1087      dfb_surface_globalize( surface );
1088 
1089      stack->cursor.surface = surface;
1090 
1091      return DFB_OK;
1092 }
1093 
1094