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, ¬ification, 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( ®ions[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 = ®ions[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 = ®ions[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