WindowSystems: Added support for DirectFB
[profile/ivi/layer-management.git] / LayerManagerPlugins / Renderers / Graphic / src / WindowSystems / DFBWindowSystem.cpp
1 /***************************************************************************
2  *
3  * Copyright (c) 2013 DirectFB integrated media GmbH
4  * Copyright (c) 2013 Renesas Solutions Corp.
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ****************************************************************************/
20
21 #include "DFBRenderer.h"
22 #include "WindowSystems/DFBWindowSystem.h"
23 #include "config.h"
24 #include "Layer.h"
25 #include <time.h>
26 #include <sys/time.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <iomanip>
32
33 typedef struct sManagedWindow
34 {
35      DFBPlatformSurface *platform;
36      DFBWindowID winID;
37      IDirectFBWindow *win;
38      DFBSurfaceID surfID;
39      IDirectFBSurface *surf;
40      int x;
41      int y;
42      int w;
43      int h;
44 } sManagedWindow;
45
46 DFBWindowSystem::DFBWindowSystem(int width, int height, Scene* pScene, InputManager* pInputManager, IDirectFB *dfb, IDirectFBDisplayLayer *layer)
47 : BaseWindowSystem(pScene, pInputManager)
48 , takeScreenshot(ScreenShotNone)
49 , screenShotFile()
50 , screenShotSurfaceID(0)
51 , screenShotLayerID()
52 , screenShotScreenID(0)
53 , resolutionWidth(width)
54 , resolutionHeight(height)
55 , m_running(false)
56 , m_initialized(false)
57 , m_checkWindows(false)
58 , m_primary_width(width)
59 , m_primary_height(height)
60 , m_mouse_x(0)
61 , m_mouse_y(0)
62 , m_mouse_x_min(-1)
63 , m_mouse_y_min(-1)
64 , m_mouse_x_max(-1)
65 , m_mouse_y_max(-1)
66 , m_adjusted_mouse_x(0)
67 , m_adjusted_mouse_y(0)
68 , m_iterationCounter(0)
69 , m_maxIterationDurationInMS(0)
70 , m_dfb(dfb)
71 , m_layer(layer)
72 , dfbDisplay(0)
73 , m_primary(NULL)
74 , renderThread(0)
75 , windowWidth(width)
76 , windowHeight(height)
77 , m_dfb_mode_hw(true)
78 , m_ignore_surface_updates(false)
79 , CompositorSurface(0)
80 , m_events(NULL)
81 , m_gfx(NULL)
82 {
83      pthread_mutex_init( &run_lock, NULL );
84      pthread_mutex_init( &init_lock, NULL );
85      pthread_cond_init( &init_condition,NULL );
86      direct_hash_init( &window_map, 17 );
87      direct_hash_init( &surface_map, 17 );
88      m_sceneLayers = new std::list<int>;
89 }
90
91 DFBWindowSystem::~DFBWindowSystem()
92 {
93      pthread_mutex_destroy( &run_lock );
94      pthread_mutex_destroy( &init_lock );
95      pthread_cond_destroy( &init_condition );
96      direct_hash_deinit( &window_map );
97      direct_hash_deinit( &surface_map );
98 }
99
100 bool DFBWindowSystem::isWindowValid(DFBWindow w)
101 {
102      sManagedWindow *win = (sManagedWindow *)direct_hash_lookup( &window_map, w );
103      if (!win)
104           return true;
105
106      return (w != 0 && win->surfID != CompositorSurface);
107 }
108
109 Surface* DFBWindowSystem::getSurfaceForWindow(DFBWindow w)
110 {
111      const std::map<unsigned int,Surface*> surfaces = m_pScene->getAllSurfaces();
112      for (std::map<unsigned int, Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); ++currentS) {
113           Surface* currentSurface = (*currentS).second;
114           if (!currentSurface)
115                continue;
116
117           if (currentSurface->getNativeContent() == static_cast<long>(w))
118                return currentSurface;
119      }
120
121      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": could not get surface for window " << w );
122
123      return NULL;
124 }
125
126 bool DFBWindowSystem::deleteOrphanWindow(void *win)
127 {
128      sManagedWindow *managed = (sManagedWindow *)win;
129
130      if (!getSurfaceForWindow( managed->winID )) {
131           LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": removing orphan window " << managed->winID );
132
133           direct_hash_remove( &window_map, managed->winID );
134           direct_hash_remove( &surface_map, managed->surfID );
135
136           managed->win->DetachEventBuffer( managed->win, m_events );
137           managed->surf->DetachEventBuffer( managed->surf, m_events );
138
139           delete managed->platform;
140
141           return true;
142      }
143
144      return false;
145 }
146
147 bool checkOrphanWindow(DirectHash *hash, unsigned long key, void *value, void *ctx)
148 {
149      (void)hash;
150      (void)key;
151      DFBWindowSystem *windowsys = static_cast<DFBWindowSystem *>((DFBWindowSystem *)ctx);
152
153      windowsys->deleteOrphanWindow( value );
154
155      return true;
156 }
157
158 void DFBWindowSystem::checkForNewSurfaceNativeContent()
159 {
160      m_pScene->lockScene();
161
162      LayerList layers = m_pScene->getCurrentRenderOrder(0);
163      for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++) {
164           SurfaceList surfaces = (*current)->getAllSurfaces();
165           for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++) {
166                if ((*currentS)->getNativeContent())
167                     allocatePlatformSurface( *currentS );
168                else
169                     deallocatePlatformSurface( *currentS );
170           }
171      }
172
173      if (direct_hash_count( &window_map ))
174           direct_hash_iterate( &window_map, checkOrphanWindow, this );
175
176      m_pScene->unlockScene();
177
178      m_checkWindows = false;
179 }
180
181 void DFBWindowSystem::configureSurfaceWindow(DFBWindow window)
182 {
183      if (isWindowValid( window )) {
184           int winWidth = 0;
185           int winHeight = 0;
186
187           UnMapWindow( window );
188           MapWindow( window );
189
190           Surface* surface = getSurfaceForWindow( window );
191           if (!surface) {
192                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find surface for window " << window );
193                return;
194           }
195
196           if (!surface->platform) {
197                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Platform surface not available for window " << window );
198                return;
199           }
200
201           DFBPlatformSurface* platformSurface = (DFBPlatformSurface*)surface->platform;
202           platformSurface->dfb_surface->GetSize( platformSurface->dfb_surface, &winWidth, &winHeight );
203
204           surface->OriginalSourceHeight = winHeight;
205           surface->OriginalSourceWidth = winWidth;
206
207           LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": successfully updated window " << window );
208      }
209 }
210
211 void DFBWindowSystem::MapWindow(DFBWindow window)
212 {
213      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(window=" << window << ")" );
214
215      if (isWindowValid( window )) {
216           Surface* surface = getSurfaceForWindow( window );
217           if (!surface) {
218                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find surface for window " << window );
219                return;
220           }
221
222           if (!surface->platform) {
223                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Platform surface not available for window " << window );
224                return;
225           }
226
227           DFBPlatformSurface* dfbsurf = (DFBPlatformSurface*)surface->platform;
228           if (dfbsurf->isMapped) {
229                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Platform surface for window " << window << " was already mapped" );
230                return;
231           }
232
233           dfbsurf->isMapped = true;
234
235           sManagedWindow *win = (sManagedWindow *)malloc( sizeof(sManagedWindow) );
236           win->platform = dfbsurf;
237           win->winID = dfbsurf->dfb_window_id;
238           win->win = dfbsurf->dfb_window;
239           win->surfID = dfbsurf->dfb_surface_id;
240           win->surf = dfbsurf->dfb_surface;
241           dfbsurf->dfb_window->GetPosition( dfbsurf->dfb_window, &win->x, &win->y );
242           dfbsurf->dfb_window->GetSize( dfbsurf->dfb_window, &win->w, &win->h );
243
244           direct_hash_insert( &window_map, dfbsurf->dfb_window_id, win );
245           direct_hash_insert( &surface_map, dfbsurf->dfb_surface_id, win );
246
247           surface->OriginalSourceWidth = win->w;
248           surface->OriginalSourceHeight = win->h;
249           surface->renderPropertyChanged = true;
250
251           m_gfx->getTextureBinder()->createClientBuffer( surface );
252           dfbsurf->enableRendering();
253
254           LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": successfully mapped window " << window );
255      }
256 }
257
258 void DFBWindowSystem::UnMapWindow(DFBWindow window)
259 {
260      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(window=" << window << ")" );
261
262      if (isWindowValid( window )) {
263           Surface* surface = getSurfaceForWindow( window );        
264           if (!surface) {
265                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find surface for window " << window );
266                return;
267           }
268
269           if (!surface->platform) {
270                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Platform surface not available for window " << window );
271                return;
272           }
273
274           DFBPlatformSurface* dfbsurf = (DFBPlatformSurface*)surface->platform;
275           dfbsurf->disableRendering();
276           if (!dfbsurf->isMapped) {
277                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Platform surface for window " << window << " was already unmapped" );
278                return;
279           }
280
281           dfbsurf->isMapped = false;
282           m_gfx->getTextureBinder()->destroyClientBuffer( surface );
283
284           if (dfbsurf->dfb_surface) {
285                dfbsurf->dfb_window->DetachEventBuffer( dfbsurf->dfb_window, m_events );
286                dfbsurf->dfb_surface->DetachEventBuffer( dfbsurf->dfb_surface, m_events );
287                direct_hash_remove( &window_map, dfbsurf->dfb_window_id );
288                direct_hash_remove( &surface_map, dfbsurf->dfb_surface_id );
289                dfbsurf->dfb_surface->Release( dfbsurf->dfb_surface );
290                dfbsurf->dfb_window->Release( dfbsurf->dfb_window );
291           }
292
293           surface->renderPropertyChanged = true;
294
295           LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": successfully unmapped window " << window );
296      }
297 }
298
299 bool DFBWindowSystem::NewWindow(Surface* surface, DFBWindow window)
300 {
301      DFBResult ret;
302      int winWidth = 0;
303      int winHeight = 0;
304
305      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(surface=" << surface << ", window=" << window << ")" );
306
307      if (isWindowValid( window )) {
308           surface->setNativeContent( window );
309           DFBPlatformSurface *platformSurface = (DFBPlatformSurface*)m_gfx->getTextureBinder()->createPlatformSurface( surface );
310           platformSurface->isMapped = false;
311
312           if (!platformSurface->dfb_surface) {
313                LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": failed to create platform surface for window " << window );
314                delete platformSurface;
315                return false;
316           }
317
318           surface->platform = platformSurface;
319
320           platformSurface->dfb_window->GetSize( platformSurface->dfb_window, &winWidth, &winHeight );
321
322           ret = platformSurface->dfb_window->AttachEventBuffer( platformSurface->dfb_window, m_events );
323           if (ret) {
324                LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": IDirectFBSurface::AttachEventBuffer() failed! (ret=" << ret << ")" );
325                delete platformSurface;
326                surface->platform = NULL;
327                return false;
328           }
329
330           ret = platformSurface->dfb_surface->AttachEventBuffer( platformSurface->dfb_surface, m_events );
331           if (ret) {
332                LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": IDirectFBSurface::AttachEventBuffer() failed! (ret=" << ret << ")" );
333                delete platformSurface;
334                surface->platform = NULL;
335                return false;
336           }
337
338           platformSurface->dfb_surface->MakeClient( platformSurface->dfb_surface );
339           surface->OriginalSourceHeight = winHeight;
340           surface->OriginalSourceWidth = winWidth;
341
342           LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": successfully created new surface " << platformSurface->dfb_surface << " for window " << window << " (w=" << winWidth << " h=" << winHeight << ")" );
343
344           return true;
345      }
346
347      return false;
348 }
349
350 void DFBWindowSystem::DestroyWindow(DFBWindow window)
351 {
352      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(window=" << window << ")" );
353
354      if (isWindowValid( window )) {
355           Surface* surface = getSurfaceForWindow( window );
356           if (!surface) {
357                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find surface for window " << window );
358                return;
359           }
360
361           m_gfx->getTextureBinder()->destroyClientBuffer( surface );
362           UnMapWindow( window );
363           surface->removeNativeContent();
364
365           surface->renderPropertyChanged = true;
366           delete surface->platform;
367           surface->platform = NULL;
368      }
369 }
370
371 int DFBWindowSystem::selectOutput(DFBGraphicSystem *gfx, int id)
372 {
373      int ret = -1;
374
375      for (int i = 0; i < gfx->m_renderer->m_num_outputs; i++) {
376           if (gfx->m_renderer->m_outputs[i].layer_id == id) {
377                ret = i;
378                break;
379           }
380      }
381
382      return ret;
383 }
384
385 void DFBWindowSystem::RedrawAllLayers(bool clear, bool swap)
386 {
387      DFBGraphicSystem *gfx;
388      DFBDisplayLayerConfig config;
389
390      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(clear=" << clear << ", swap=" << swap << ")" );
391
392      LayerList layers = m_pScene->getCurrentRenderOrder( 0 );
393      LayerList swLayers;
394      std::list<int> orphan_ids = list<int>( *m_sceneLayers );
395
396      m_sceneLayers->clear();
397
398      for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++) {
399           m_sceneLayers->push_back( (*current)->getID() );
400           orphan_ids.remove( (*current)->getID() );
401
402           if ((*current)->getLayerType() == Hardware) {
403                if (m_forceComposition || m_gfx->needsRedraw( *current ))
404                     renderHWLayer( *current, clear );
405           }
406           else
407                swLayers.push_back( *current );
408      }
409
410      if (m_dfb_mode_hw) {
411           gfx = (DFBGraphicSystem *)m_gfx;
412
413           for(std::list<int>::iterator list_iter = orphan_ids.begin(); list_iter != orphan_ids.end(); list_iter++) {
414                int output = selectOutput( gfx, *list_iter );
415                if (output >= 0) {
416                     if (!gfx->m_renderer->m_outputs[output].muted) {
417                          LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": turning OFF orphan layer " << gfx->m_renderer->m_outputs[output].layer );
418
419                          if (!gfx->m_renderer->m_outputs[output].layer->GetConfiguration( gfx->m_renderer->m_outputs[output].layer, &config )) {
420                               config.options = DLOP_OPACITY;
421
422                               if (gfx->m_renderer->m_outputs[output].layer->SetConfiguration( gfx->m_renderer->m_outputs[output].layer, &config )) {
423                                    LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set layer configuration on layer " << gfx->m_renderer->m_outputs[output].layer );
424                               }
425                               else {
426                                    if (gfx->m_renderer->m_outputs[output].layer->SetOpacity( gfx->m_renderer->m_outputs[output].layer, 0 )) {
427                                         LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set opacity on layer " << gfx->m_renderer->m_outputs[output].layer );
428                                    }
429                                    else {
430                                         gfx->m_renderer->m_outputs[output].muted = true;
431                                         gfx->m_renderer->m_outputs[output].layer_opacity = 0;
432                                    }
433                               }
434                          }
435                     }
436                }
437           }
438      }
439
440      if (swLayers.size() > 0 && (m_forceComposition || m_gfx->needsRedraw( swLayers ))) {
441           if (m_dfb_mode_hw)
442                renderSWLayers( swLayers, clear, swap );
443           else {
444                m_gfx->renderSWLayers( swLayers, clear );
445
446                if (swap)
447                     m_gfx->swapBuffers();
448           }
449      }
450 }
451
452 void DFBWindowSystem::renderSWLayers(LayerList layers, bool clear, bool swap)
453 {
454      DFBGraphicSystem *gfx = (DFBGraphicSystem *)m_gfx;
455
456      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(clear=" << clear << ", swap=" << swap << ")" );
457
458      for (LayerListConstIterator layer = layers.begin(); layer != layers.end(); layer++) {
459           gfx->renderSWLayer( *layer, clear );
460           if (swap) {
461                gfx->beginLayer( *layer );
462                if (gfx->m_renderer_output == -1) {
463                     LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": called with a non-existent layer" );
464                     gfx->endLayer();
465                     continue;
466                }
467                gfx->swapBuffers();
468                gfx->endLayer();
469           }
470      }
471 }
472
473 static int countVisibleSurfaces(Layer *layer)
474 {
475      int ret = 0;
476      FloatRectangle rect;
477
478      SurfaceList surfaces = layer->getAllSurfaces();
479      for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++) {
480           if ((*currentS)->getOpacity() > 0 && (*currentS)->getVisibility()) {
481                rect = (*currentS)->getTargetSourceRegion();
482                if (rect.width > 0 && rect.height > 0) {
483                     rect = (*currentS)->getTargetDestinationRegion();
484                     if (rect.width > 0 && rect.height > 0)
485                          ret++;
486                }
487           }
488      }
489
490      return ret;
491 }
492
493 static bool isSurfaceVisible(Surface *surface)
494 {
495      FloatRectangle rect;
496
497      if (surface->getOpacity() > 0 && surface->getVisibility()) {
498           rect = surface->getTargetSourceRegion();
499           if (rect.width > 0 && rect.height > 0) {
500                rect = surface->getTargetDestinationRegion();
501                if (rect.width > 0 && rect.height > 0)
502                     return true;
503           }
504      }
505
506      return false;
507 }
508
509 void DFBWindowSystem::renderHWLayer(Layer *layer, bool clear)
510 {
511      DFBGraphicSystem *gfx = (DFBGraphicSystem *)m_gfx;
512      DFBDisplayLayerConfig config;
513      int num_surfaces_curr = 0;
514
515      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(layer=" << layer << ", clear=" << clear << ")" );
516
517      gfx->beginLayer( layer );
518      if (gfx->m_renderer_output == -1) {
519           LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": called with a non-existent layer" );
520
521           gfx->endLayer();
522           return;
523      }
524
525      if (layer->getLayerType() != Hardware)
526           LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": called with a non-HW layer" );
527
528      if (!m_pScene->isLayerInCurrentRenderOrder( layer->getID() ) || layer->opacity == 0 || layer->visibility == 0) {
529           if (!gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted) {
530                LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": turning OFF layer " << layer);
531
532                if (!gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->GetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
533                     config.options = DLOP_OPACITY;
534
535                     if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
536                          LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set layer configuration on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
537                     }
538                     else {
539                          if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetOpacity( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, 0 )) {
540                               LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set opacity on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
541                          }
542                          else {
543                               gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted = true;
544                               gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer_opacity = 0;
545                          }
546                     }
547                }
548           }
549      }
550      else if (layer->visibility > 0 && layer->opacity > 0.0f) {
551           num_surfaces_curr = countVisibleSurfaces( layer );
552           if (num_surfaces_curr > 0) {
553                if (layer->getChromaKeyEnabled())
554                     LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": cannot handle chroma key" );
555
556                if (clear)
557                     gfx->clearBackground();
558
559                if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted || gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer_opacity != layer->opacity) {
560                     LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": turning ON layer " << layer << " with opacity=" << (int)(layer->opacity * 0xFF) );
561
562                     if (!gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->GetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
563                          config.options = layer->opacity == 1 ? DLOP_NONE : (DFBDisplayLayerOptions)(DLOP_OPACITY | DLOP_ALPHACHANNEL);
564
565                          if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
566                               LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set layer configuration on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
567                          }
568                          else {
569                               if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetOpacity( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, layer->opacity * 0xFF )) {
570                                    LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set opacity on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
571                               }
572                               else {
573                                    gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted = false;
574                                    gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer_opacity = layer->opacity;
575                               }
576                          }
577                     }
578                }
579
580                SurfaceList surfaces = layer->getAllSurfaces();
581                for (std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); ++currentS) {
582                     if ((*currentS)->hasNativeContent() && isSurfaceVisible( (*currentS) ))
583                          gfx->renderSurface( *currentS );
584                }
585           }
586           else if (!gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted) {
587                LOG_INFO( "DFBWindowSystem", __FUNCTION__ << ": tunring OFF layer " << layer);
588
589                if (!gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->GetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
590                     config.options = DLOP_OPACITY;
591
592                     if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetConfiguration( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, &config )) {
593                          LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set layer configuration on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
594                     }
595                     else {
596                          if (gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer->SetOpacity( gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer, 0 )) {
597                               LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": failed to set opacity on layer " << gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer );
598                          }
599                          else {
600                               gfx->m_renderer->m_outputs[gfx->m_renderer_output].muted = true;
601                               gfx->m_renderer->m_outputs[gfx->m_renderer_output].layer_opacity = 0;
602                          }
603                     }
604                }
605           }
606
607           gfx->m_renderer->m_outputs[gfx->m_renderer_output].num_surfaces = num_surfaces_curr;
608      }
609
610      gfx->swapBuffers();
611
612      gfx->endLayer();
613 }
614
615 void DFBWindowSystem::Redraw(bool clear)
616 {
617      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "()" );
618
619      m_pScene->lockScene();
620
621      RedrawAllLayers( clear, true );
622      ClearDamage();
623
624      m_pScene->unlockScene();
625 }
626
627 void DFBWindowSystem::Screenshot()
628 {
629      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "()" );
630
631      m_pScene->lockScene();
632
633      if (takeScreenshot == ScreenshotOfDisplay) {
634           if (!m_dfb_mode_hw) {
635                RedrawAllLayers( true, false );
636                m_gfx->saveScreenShotOfFramebuffer( screenShotFile );
637           }
638           else
639                LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": Screetshot of FrameBuffer currently unsupported!" );
640      }
641      else if (takeScreenshot == ScreenshotOfLayer) {
642           Layer* layer = m_pScene->getLayer( screenShotLayerID );
643           if (layer != NULL) {
644                m_gfx->renderSWLayer( layer, true );
645                if (m_dfb_mode_hw)
646                     m_gfx->beginLayer( layer );
647                m_gfx->saveScreenShotOfFramebuffer( screenShotFile );
648                if (m_dfb_mode_hw)
649                     m_gfx->endLayer();
650           }
651      }
652      else if (takeScreenshot == ScreenshotOfSurface) {
653           Layer* layer = m_pScene->getLayer( screenShotLayerID );
654           Surface* surface = m_pScene->getSurface( screenShotSurfaceID );
655           if (layer != NULL && surface != NULL) {
656                m_gfx->clearBackground();
657                m_gfx->beginLayer( layer );
658                m_gfx->renderSurface( surface );
659                m_gfx->saveScreenShotOfFramebuffer( screenShotFile );
660                m_gfx->endLayer();
661           }
662      }
663
664      takeScreenshot = ScreenShotNone;
665
666      m_pScene->unlockScene();
667 }
668
669 void *startEventLoop(void *ptr)
670 {
671      DFBWindowSystem *windowsys = static_cast<DFBWindowSystem *>((DFBWindowSystem *)ptr);
672      windowsys->EventLoop();
673
674      return NULL;
675 }
676
677 static void genWindowEventFromInput(const DFBInputEvent *inputEvent, DFBWindowID wid, DFBWindowEventType etype, int x, int y, int cx, int cy, DFBWindowEvent *windowEvent)
678 {
679      memset( windowEvent, 0, sizeof(DFBWindowEvent) );
680
681      windowEvent->type = etype;
682      windowEvent->window_id = wid; 
683      windowEvent->flags = DWEF_DEVICE_ID;
684      windowEvent->x = x;
685      windowEvent->y = y;
686      windowEvent->cx = cx;
687      windowEvent->cy = cy;
688      windowEvent->device_id = inputEvent->device_id;
689      windowEvent->timestamp = inputEvent->timestamp;
690      windowEvent->key_code = inputEvent->key_code;
691      windowEvent->key_id = inputEvent->key_id;
692      windowEvent->key_symbol = inputEvent->key_symbol;
693      windowEvent->modifiers = inputEvent->modifiers;
694      windowEvent->locks = inputEvent->locks;
695      windowEvent->button = inputEvent->button;
696      windowEvent->buttons = inputEvent->buttons;
697 }
698
699 void DFBWindowSystem::EventLoop()
700 {
701      Surface *surface;
702      sManagedWindow *win;
703      DFBPlatformSurface *surf;
704      DFBWindowEvent windowEvent;
705      DFBEvent event;
706      bool redraw = false;
707
708      if (m_primary) {
709           LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": using compositor primary " << m_primary << " with id " << CompositorSurface << " (w=" << m_primary_width << " h=" << m_primary_height << ")" );
710
711           m_primary->Clear( m_primary, 0, 0, 0, 0 );
712           m_primary->Flip( m_primary, NULL, DSFLIP_NONE );
713      
714           m_gfx->init( dfbDisplay, (long)m_primary );
715           m_gfx->activateGraphicContext();
716           m_gfx->clearBackground();
717           m_gfx->swapBuffers();
718      }
719
720      pthread_mutex_lock( &init_lock );
721      m_running = true;
722      pthread_cond_signal( &init_condition );
723      pthread_mutex_unlock( &init_lock );
724
725      while (m_running) {
726           if (m_checkWindows) {
727                checkForNewSurfaceNativeContent();
728                Redraw( true );
729                redraw = false;
730           }
731           else if (redraw) {
732                Redraw( true );
733                redraw = false;
734           }
735
736           if (takeScreenshot != ScreenShotNone)
737                Screenshot();
738
739           m_events->WaitForEventWithTimeout( m_events, 0, 300 );
740
741           pthread_mutex_lock( &run_lock );
742
743           while (m_events->GetEvent( m_events, &event ) == DFB_OK) {
744                switch (event.clazz) {
745                     case DFEC_WINDOW:
746                          switch (event.window.type) {
747                               case DWET_POSITION:
748                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": WINDOW POSITION event for window id " << event.window.window_id );
749
750                                    win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
751                                    if (win) {
752                                         win->x = event.window.x;
753                                         win->y = event.window.y;
754                                    }
755                                    else
756                                         LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
757                                    break;
758                               default:
759                                    break;
760                          }
761                          break;
762                     case DFEC_SURFACE:
763                          switch (event.surface.type) {
764                               case DSEVT_UPDATE:
765                                    if (!m_ignore_surface_updates) {
766                                         LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": SURFACE UPDATE event for surface id " << event.surface.surface_id );
767
768                                         win = (sManagedWindow *)direct_hash_lookup( &surface_map, event.surface.surface_id );
769                                         if (win) {
770                                              LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": sending FrameAck for surface id " << event.surface.surface_id << " (frame=" << event.surface.flip_count << ")" );
771                                              win->surf->FrameAck( win->surf, event.surface.flip_count );
772                                              redraw = true;
773                                         }
774                                         else
775                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find surface for id " << event.surface.surface_id );
776                                    }
777                                    else
778                                         LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": SURFACE UPDATE event for surface id " << event.surface.surface_id << " -- ignoring" );
779                                    break;
780                               default:
781                                    break;
782                          }
783                          break;
784                     case DFEC_INPUT:
785                          Point pos;
786                          pos.x = m_adjusted_mouse_x;
787                          pos.y = m_adjusted_mouse_y;
788                          switch (event.input.type) {
789                               case DIET_KEYPRESS:
790                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> KEYPRESS" );
791
792                                    surface = m_pInputManager->reportKeyboardEvent( INPUT_STATE_PRESSED, event.input.key_code );
793                                    if (surface && surface->platform) {
794                                         surf = (DFBPlatformSurface *)surface->platform;
795                                         win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
796                                         if (!win) {
797                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
798                                              break;
799                                         }
800                                         genWindowEventFromInput( &event.input, surf->dfb_window_id, DWET_KEYDOWN, m_adjusted_mouse_x, m_adjusted_mouse_y, m_adjusted_mouse_x - win->x, m_adjusted_mouse_y - win->y, &windowEvent );
801                                         win->win->SendEvent( win->win, &windowEvent );
802                                    }
803                                    break;
804                               case DIET_KEYRELEASE:
805                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> KEYRELEASE" );
806
807                                    surface = m_pInputManager->reportKeyboardEvent( INPUT_STATE_RELEASED, event.input.key_code );
808                                    if (surface && surface->platform) {
809                                         surf = (DFBPlatformSurface *)surface->platform;
810                                         win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
811                                         if (!win) {
812                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
813                                              break;
814                                         }
815                                         genWindowEventFromInput( &event.input, surf->dfb_window_id, DWET_KEYUP, m_adjusted_mouse_x, m_adjusted_mouse_y, m_adjusted_mouse_x - win->x, m_adjusted_mouse_y - win->y, &windowEvent );
816                                         win->win->SendEvent( win->win, &windowEvent );
817                                    }
818                                    break;
819                               case DIET_BUTTONPRESS:
820                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> BUTTONPRESS" );
821
822                                    pos.state = INPUT_STATE_PRESSED;
823                                    surface = m_pInputManager->reportPointerEvent( pos );
824                                    if (surface && surface->platform) {
825                                         surf = (DFBPlatformSurface *)surface->platform;
826                                         win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
827                                         if (!win) {
828                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
829                                              break;
830                                         }
831                                         genWindowEventFromInput( &event.input, surf->dfb_window_id, DWET_BUTTONDOWN, m_adjusted_mouse_x, m_adjusted_mouse_y, m_adjusted_mouse_x - win->x, m_adjusted_mouse_y - win->y, &windowEvent );
832                                         win->win->SendEvent( win->win, &windowEvent );
833                                    }
834                                    break;
835                               case DIET_BUTTONRELEASE:
836                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> BUTTONRELEASE" );
837
838                                    pos.state = INPUT_STATE_RELEASED;
839                                    surface = m_pInputManager->reportPointerEvent( pos );
840                                    if (surface && surface->platform) {
841                                         surf = (DFBPlatformSurface *)surface->platform;
842                                         win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
843                                         if (!win) {
844                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
845                                              break;
846                                         }
847                                         genWindowEventFromInput( &event.input, surf->dfb_window_id, DWET_BUTTONUP, m_adjusted_mouse_x, m_adjusted_mouse_y, m_adjusted_mouse_x - win->x, m_adjusted_mouse_y - win->y, &windowEvent );
848                                         win->win->SendEvent( win->win, &windowEvent );
849                                    }
850                                    break;
851                               case DIET_AXISMOTION:
852                                    pos.state = INPUT_STATE_MOTION;
853                                    if (event.input.flags & DIEF_AXISABS) {
854                                         switch (event.input.axis) {
855                                              case DIAI_X:
856                                                   m_mouse_x = event.input.axisabs;
857                                                   m_mouse_x_min = event.input.min;
858                                                   m_mouse_x_max = event.input.max;
859                                                   break;
860                                              case DIAI_Y:
861                                                   m_mouse_y = event.input.axisabs;
862                                                   m_mouse_y_min = event.input.min;
863                                                   m_mouse_y_max = event.input.max;
864                                                   break;
865                                              default:
866                                                   break;
867                                         }
868                                    }
869                                    else if (event.input.flags & DIEF_AXISREL) {
870                                         switch (event.input.axis) {
871                                              case DIAI_X:
872                                                   m_mouse_x += event.input.axisrel;
873                                                   break;
874                                              case DIAI_Y:
875                                                   m_mouse_y += event.input.axisrel;
876                                                   break;
877                                              default:
878                                                   break;
879                                         }
880                                    }
881
882                                    if (m_mouse_y_min < m_mouse_y_max && m_mouse_x_min < m_mouse_x_max) {
883                                         m_adjusted_mouse_x = CLAMP(m_mouse_x, 0, m_mouse_x_max);
884                                         m_adjusted_mouse_y = CLAMP(m_mouse_y, 0, m_mouse_y_max);
885                                         m_adjusted_mouse_x = ((m_primary_width - 1) * m_adjusted_mouse_x) / m_mouse_x_max;
886                                         m_adjusted_mouse_y = ((m_primary_height - 1) * m_adjusted_mouse_y) / m_mouse_y_max;
887                                    }
888                                    else {
889                                         m_adjusted_mouse_x = CLAMP(m_mouse_x, 0, m_primary_width - 1);
890                                         m_adjusted_mouse_y = CLAMP(m_mouse_y, 0, m_primary_height - 1);
891                                    }
892
893                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> MOTION at " << m_adjusted_mouse_x << "," << m_adjusted_mouse_y );
894
895                                    pos.x = m_adjusted_mouse_x;
896                                    pos.y = m_adjusted_mouse_y;
897
898                                    surface = m_pInputManager->reportPointerEvent( pos );
899                                    if (surface && surface->platform) {
900                                         surf = (DFBPlatformSurface *)surface->platform;
901                                         win = (sManagedWindow *)direct_hash_lookup( &window_map, event.window.window_id );
902                                         if (!win) {
903                                              LOG_WARNING( "DFBWindowSystem", __FUNCTION__ << ": could not find window for id " << event.window.window_id );
904                                              break;
905                                         }
906                                         genWindowEventFromInput( &event.input, surf->dfb_window_id, DWET_MOTION, m_adjusted_mouse_x, m_adjusted_mouse_y, m_adjusted_mouse_x - win->x, m_adjusted_mouse_y - win->y, &windowEvent );
907                                         win->win->SendEvent( win->win, &windowEvent );
908                                    }
909                                    break;
910                               default:
911                                    LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> UNKNOWN INPUT EVENT" );
912                                    break;
913                          }
914                          break;
915                     default:
916                          break;
917                }
918           }
919
920           pthread_mutex_unlock( &run_lock );
921      }
922
923      cleanup();
924
925      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << " --> finished" );
926 }
927
928 void DFBWindowSystem::signalRedrawEvent()
929 {
930      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "()" );
931
932      pthread_mutex_lock( &run_lock );
933
934      m_checkWindows = true;
935      m_events->WakeUp( m_events );
936
937      pthread_mutex_unlock( &run_lock );
938 }
939
940 void DFBWindowSystem::cleanup()
941 {
942      pthread_mutex_lock( &run_lock );
943
944      m_running = false;
945      m_initialized = false;
946
947      if (m_events) {
948           m_events->Release( m_events );
949           m_events = NULL;
950      }
951
952      if (m_primary) {
953           m_primary->Release( m_primary );
954           m_primary = NULL;
955      }
956
957      pthread_mutex_unlock( &run_lock );
958 }
959
960 bool DFBWindowSystem::init(BaseGraphicSystem<DFBDisplay, DFBWindow>* base, bool dfb_mode_hw)
961 {
962      DFBResult ret;
963
964      LOG_INFO( "DFBWindowSystem", __FUNCTION__ << "(hw=" << dfb_mode_hw << ")" );
965
966      m_gfx = base;
967      m_dfb_mode_hw = dfb_mode_hw;
968
969      m_forceComposition = true;
970
971      ret = m_dfb->CreateInputEventBuffer( m_dfb, (DFBInputDeviceCapabilities)(DICAPS_KEYS | DICAPS_BUTTONS | DICAPS_AXES), DFB_FALSE, &m_events );
972      if (ret) {
973           LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": IDirectFB::CreateEventBuffer() failed! (ret=" << ret << ")" );
974           return false;
975      }
976
977      if (!m_dfb_mode_hw) {
978           DFBSurfaceID surf_id;
979
980           ret = m_layer->GetSurface( m_layer, &m_primary );
981           if (ret) {
982                LOG_ERROR( "DFBWindowSystem", __FUNCTION__ << ": IDirectFBDisplayLayer::GetSurface() failed! (ret=" << ret << ")" );
983                m_events->Release( m_events );
984                if (m_primary)
985                     m_primary->Release( m_primary );
986      
987                return false;
988           }
989      
990           m_primary->GetSize( m_primary, &m_primary_width, &m_primary_height );
991      
992           LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << ": retrieved layer primary " << m_primary << " (w=" << m_primary_width << " h=" << m_primary_height << ")" );
993      
994           m_primary->GetID( m_primary, &surf_id );
995           CompositorSurface = surf_id;
996      }
997
998      pthread_mutex_lock( &init_lock );
999
1000      int status = pthread_create( &renderThread, NULL, startEventLoop, this );
1001      if (status) {
1002           pthread_mutex_unlock( &init_lock );
1003           return false;
1004      }
1005
1006      if (!m_running)
1007           pthread_cond_wait( &init_condition, &init_lock );
1008
1009      pthread_mutex_unlock( &init_lock );
1010
1011      LOG_INFO( "DFBWindowSystem", __FUNCTION__ << " --> initialized" );
1012
1013      return true;
1014 }
1015
1016 bool DFBWindowSystem::start(int maxIterationDurationInMS)
1017 {
1018      LOG_INFO( "DFBWindowSystem", __FUNCTION__ << "(" << maxIterationDurationInMS << ")" );
1019
1020      pthread_mutex_lock( &run_lock );
1021
1022      LayerList layers = m_pScene->getCurrentRenderOrder( 0 );
1023      for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
1024           m_sceneLayers->push_back( (*current)->getID() );
1025
1026      m_maxIterationDurationInMS = maxIterationDurationInMS;
1027
1028      m_running = true;
1029
1030      m_checkWindows = true;
1031      m_events->WakeUp( m_events );
1032
1033      pthread_mutex_unlock( &run_lock );
1034
1035      return true;
1036 }
1037
1038 void DFBWindowSystem::stop()
1039 {
1040      LOG_INFO( "DFBWindowSystem", __FUNCTION__ << "()" );
1041
1042      pthread_mutex_lock( &run_lock );
1043
1044      m_sceneLayers->clear();
1045
1046      m_running = false;
1047      m_events->WakeUp( m_events );
1048
1049      pthread_mutex_unlock( &run_lock );
1050
1051      pthread_join( renderThread, NULL );
1052 }
1053
1054 void DFBWindowSystem::allocatePlatformSurface(Surface* surface)
1055 {
1056      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(" << surface << ")" );
1057
1058      DFBPlatformSurface* nativeSurface = (DFBPlatformSurface*)surface->platform;
1059      if (!nativeSurface) {
1060           if (NewWindow( surface, surface->getNativeContent() ))
1061                MapWindow( surface->getNativeContent() );
1062      }
1063 }
1064
1065 void DFBWindowSystem::deallocatePlatformSurface(Surface* surface)
1066 {
1067      LOG_DEBUG( "DFBWindowSystem", __FUNCTION__ << "(" << surface << ")" );
1068
1069      DFBPlatformSurface* nativeSurface = (DFBPlatformSurface*)surface->platform;
1070      if (nativeSurface) {
1071           m_gfx->getTextureBinder()->destroyClientBuffer( surface );
1072
1073           if (nativeSurface->dfb_surface)
1074                nativeSurface->dfb_surface->Release( nativeSurface->dfb_surface );
1075
1076           if (nativeSurface->dfb_window)
1077                nativeSurface->dfb_window->Release( nativeSurface->dfb_window );
1078
1079           surface->renderPropertyChanged = true;
1080           delete surface->platform;
1081           surface->platform = NULL;
1082      }
1083 }
1084
1085 void DFBWindowSystem::doScreenShot(std::string fileName, const uint screen_id)
1086 {
1087      takeScreenshot = ScreenshotOfDisplay;
1088      screenShotFile = fileName;
1089      screenShotScreenID = screen_id;
1090 }
1091
1092 void DFBWindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1093 {
1094      takeScreenshot = ScreenshotOfLayer;
1095      screenShotFile = fileName;
1096      screenShotLayerID = id;
1097 }
1098
1099 void DFBWindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1100 {
1101      takeScreenshot = ScreenshotOfSurface;
1102      screenShotFile = fileName;
1103      screenShotSurfaceID = id;
1104      screenShotLayerID = layer_id;
1105 }
1106
1107 DFBDisplay DFBWindowSystem::getNativeDisplayHandle()
1108 {
1109      return dfbDisplay;
1110 }
1111
1112 int DFBWindowSystem::getIterationCounter()
1113 {
1114      return m_iterationCounter;
1115 }
1116