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, ®ion, 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