remove debug
[enigma2.git] / lib / gui / ewidgetdesktop.cpp
1 #include <lib/gui/ewidgetdesktop.h>
2 #include <lib/gui/ewidget.h>
3 #include <lib/base/ebase.h>
4 #include <lib/gdi/grc.h>
5
6 extern void dumpRegion(const gRegion &region);
7
8 void eWidgetDesktop::addRootWidget(eWidget *root)
9 {
10         assert(!root->m_desktop);
11         
12         int invert_sense = 0;
13                 /* buffered mode paints back-to-front, while immediate mode is front-to-back. */
14         if (m_comp_mode == cmBuffered)
15                 invert_sense = 1;
16         
17         ePtrList<eWidget>::iterator insert_position = m_root.begin();
18         
19         for (;;)
20         {
21                 if ((insert_position == m_root.end()) || (invert_sense ^ (insert_position->m_z_position < root->m_z_position)))
22                 {
23                         m_root.insert(insert_position, root);
24                         break;
25                 }
26                 ++insert_position;
27         }
28         
29         root->m_desktop = this;
30
31                 /* the creation will be postponed. */
32         root->m_comp_buffer = 0;
33 }
34
35 void eWidgetDesktop::removeRootWidget(eWidget *root)
36 {
37         if (m_comp_mode == cmBuffered)
38                 removeBufferForWidget(root);
39
40         m_root.remove(root);
41 }
42
43 int eWidgetDesktop::movedWidget(eWidget *root)
44 {
45         if ((m_comp_mode == cmBuffered) && (root->m_comp_buffer))
46         {
47                 root->m_comp_buffer->m_position = root->position();
48 //              redrawComposition(0);
49                 return 0;
50         }
51         
52         return -1;
53 }
54
55 void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible)
56 {
57                 /* start with our clip region, clipped with the parent's */
58         if (widget->m_vis & eWidget::wVisShow)
59         {
60                 widget->m_visible_region = widget->m_clip_region;
61                 widget->m_visible_region.moveBy(widget->position());
62                 widget->m_visible_region &= parent_visible; // in parent space!
63
64                 if (!widget->isTransparent())
65                                 /* remove everything this widget will contain from parent's visible list, unless widget is transparent. */
66                         parent_visible -= widget->m_visible_region; // will remove child regions too!
67
68                         /* now prepare for recursing to childs */
69                 widget->m_visible_region.moveBy(-widget->position());            // now in local space
70         } else
71                 widget->m_visible_region = gRegion();
72
73         widget->m_visible_with_childs = widget->m_visible_region;
74         
75                         /* add childs in reverse (Z) order - we're going from front-to-bottom here. */
76         ePtrList<eWidget>::iterator i(widget->m_childs.end());
77         
78         for (;;)
79         {
80                 if (i != widget->m_childs.end())
81                 {
82                         if (i->m_vis & eWidget::wVisShow)
83                                 calcWidgetClipRegion(*i, widget->m_visible_region);
84                         else
85                                 clearVisibility(*i);
86                 }
87                 if (i == widget->m_childs.begin())
88                         break;
89                 --i;
90         }
91 }
92
93 void eWidgetDesktop::recalcClipRegions(eWidget *root)
94 {
95         if (m_comp_mode == cmImmediate)
96         {
97                 gRegion background_before = m_screen.m_background_region;
98                 
99                 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
100         
101                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
102                 {
103                         if (!(i->m_vis & eWidget::wVisShow))
104                         {
105                                 clearVisibility(i);
106                                 continue;
107                         }
108                         
109                         gRegion visible_before = i->m_visible_with_childs;
110
111                         calcWidgetClipRegion(*i, m_screen.m_background_region);
112                         
113                         gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
114
115                         redraw.moveBy(i->position());
116                         
117                         invalidate(redraw);
118                 }
119                 
120                 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
121                 invalidate(redraw);
122         } else if (m_comp_mode == cmBuffered)
123         {
124                 if (!root->m_vis & eWidget::wVisShow)
125                 {
126                         clearVisibility(root);
127                         removeBufferForWidget(root);
128                         return;
129                 }
130                 if ((!root->m_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
131                         createBufferForWidget(root);
132
133                 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
134
135                 gRegion visible_before = root->m_visible_with_childs;
136                  
137                 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
138                 
139                 gRegion visible_new = root->m_visible_with_childs - visible_before;
140                 gRegion visible_lost = visible_before - root->m_visible_with_childs;
141                 visible_new.moveBy(root->position());
142                 visible_lost.moveBy(root->position());
143                 
144                         /* this sucks, obviously. */
145                 invalidate(visible_new);
146                 invalidate(visible_lost);
147                 
148                 calcWidgetClipRegion(root, comp->m_background_region);
149         }
150 }
151
152 void eWidgetDesktop::invalidate(const gRegion &region)
153 {
154         if (region.empty())
155                 return;
156         
157         if (m_timer && !m_require_redraw)
158                 m_timer->start(0, 1); // start singleshot redraw timer
159         
160         m_require_redraw = 1;
161         
162         if (m_comp_mode == cmImmediate)
163                 m_screen.m_dirty_region |= region;
164         else
165                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
166                 {
167                         if (!(i->m_vis & eWidget::wVisShow))
168                                 continue;
169                         
170                         eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
171                         
172                         gRegion mregion = region;
173                         comp->m_dirty_region |= mregion;
174                 }
175 }
176
177 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
178 {
179         comp->m_background_color = col;
180         
181                 /* if there's something visible from the background, redraw it with the new color. */
182         if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
183         {
184                         /* todo: split out "setBackgroundColor / clear"... maybe? */
185                 gPainter painter(comp->m_dc);
186                 painter.resetClip(comp->m_background_region);
187                 painter.setBackgroundColor(comp->m_background_color);
188                 painter.clear();
189         }
190 }
191
192 void eWidgetDesktop::setBackgroundColor(gRGB col)
193 {
194         setBackgroundColor(&m_screen, col);
195
196         if (m_comp_mode == cmBuffered)
197                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
198                         setBackgroundColor(i->m_comp_buffer, col);
199 }
200
201 void eWidgetDesktop::setPalette(gPixmap &pm)
202 {
203 //      if (m_comp_mode == cmImmediate)
204         {
205                 ASSERT(m_screen.m_dc);
206                 gPainter painter(m_screen.m_dc);
207                 painter.setPalette(&pm);
208         }
209         
210         if (m_comp_mode == cmBuffered)
211         {
212                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
213                 {
214                         ASSERT(i->m_comp_buffer->m_dc);
215                         gPainter painter(i->m_comp_buffer->m_dc);
216                         painter.setPalette(&pm);
217                 }
218         }
219 }
220
221 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
222 {
223         comp->m_dirty_region &= comp->m_background_region;
224         
225         gPainter painter(comp->m_dc);
226         
227         painter.resetClip(comp->m_dirty_region);
228         painter.setBackgroundColor(comp->m_background_color);
229         painter.clear();
230         painter.flush();
231         
232         comp->m_dirty_region = gRegion();
233 }
234
235 void eWidgetDesktop::paint()
236 {
237         m_require_redraw = 0;
238         
239                 /* walk all root windows. */
240         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
241         {
242                 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
243                 
244                 if (!(i->m_vis & eWidget::wVisShow))
245                         continue;
246                 
247                 {
248                         gPainter painter(comp->m_dc);
249                         painter.moveOffset(-comp->m_position);
250                         i->doPaint(painter, comp->m_dirty_region);
251                         painter.resetOffset();
252                 }
253
254                 if (m_comp_mode != cmImmediate)
255                         paintBackground(comp);
256         }
257         
258         if (m_comp_mode == cmImmediate)
259                 paintBackground(&m_screen);
260         
261         if (m_comp_mode == cmBuffered)
262         {
263 //              redrawComposition(0);
264         }
265 }
266
267 void eWidgetDesktop::setDC(gDC *dc)
268 {
269         m_screen.m_dc = dc;
270         if (m_comp_mode == cmBuffered)
271                 redrawComposition(1);
272 }
273
274 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
275 {
276         if (m_mainloop)
277         {
278                 delete m_timer;
279                 m_timer = 0;
280                 m_mainloop = 0;
281         }
282         m_mainloop = &ml;
283         m_timer = new eTimer(m_mainloop);
284         CONNECT(m_timer->timeout, eWidgetDesktop::paint);
285         
286         if (m_require_redraw)
287                 m_timer->start(0, 1);
288 }
289
290 void eWidgetDesktop::makeCompatiblePixmap(ePtr<gPixmap> &pm)
291 {
292         makeCompatiblePixmap(*(pm.operator->()));
293 }
294
295 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
296 {
297         if (m_comp_mode != cmImmediate)
298                 return;
299         
300 //      eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
301         if (!m_screen.m_dc)
302         {
303                 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
304                 return;
305         }
306
307         ePtr<gPixmap> target_pixmap;
308         m_screen.m_dc->getPixmap(target_pixmap);
309         
310         assert(target_pixmap);
311         
312         if (target_pixmap->surface && target_pixmap->surface->bpp > 8)
313                 return;
314
315         ePtr<gDC> pixmap_dc = new gDC(&pm);
316         gPainter pixmap_painter(pixmap_dc);
317         
318         pixmap_painter.mergePalette(target_pixmap);
319 }
320
321 void eWidgetDesktop::setCompositionMode(int mode)
322 {
323         m_comp_mode = mode;
324         
325         if (mode == cmBuffered)
326                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
327                         createBufferForWidget(*i);
328         else
329                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
330                         removeBufferForWidget(*i);
331 }
332
333 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
334 {
335         m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
336         m_screen.m_screen_size = size;
337         m_require_redraw = 0;
338         m_style_id = 0;
339
340         CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
341         setCompositionMode(cmImmediate);
342 }
343
344 eWidgetDesktop::~eWidgetDesktop()
345 {
346                 /* tell registered root windows that they no longer have a desktop. */
347         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); )
348         {
349                 i->m_desktop = 0;
350                 i = m_root.erase(i);
351         }
352                 /* destroy all buffers */
353         setCompositionMode(-1);
354 }
355
356 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
357 {
358         removeBufferForWidget(widget);
359         
360         eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
361         
362         eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
363         
364         eRect bbox = eRect(widget->position(), widget->size());
365         comp->m_position = bbox.topLeft();
366         comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
367         comp->m_screen_size = bbox.size();
368                 /* TODO: configurable bit depth. */
369         
370                 /* clone palette. FIXME. */
371         ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
372         pm->surface->clut.data = new gRGB[256];
373         pm->surface->clut.colors = 256;
374         pm->surface->clut.start = 0;
375         
376         
377         m_screen.m_dc->getPixmap(pm_screen);
378         
379         memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
380
381         comp->m_dc = new gDC(pm);
382 }
383
384 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
385 {
386         if (widget->m_comp_buffer)
387         {
388                 delete widget->m_comp_buffer;
389                 widget->m_comp_buffer = 0;
390         }
391 }
392
393 void eWidgetDesktop::redrawComposition(int notified)
394 {
395         if (m_comp_mode != cmBuffered)
396                 return;
397         
398         assert(m_screen.m_dc);
399         
400         gPainter p(m_screen.m_dc);
401         p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
402         p.setBackgroundColor(m_screen.m_background_color);
403         p.clear();
404         
405         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
406         {
407                 if (!i->isVisible())
408                         continue;
409                 ePtr<gPixmap> pm;
410                 ASSERT(i->m_comp_buffer);
411                 i->m_comp_buffer->m_dc->getPixmap(pm);
412                 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
413         }
414
415                 // flip activates on next vsync.        
416         p.flip();
417         p.waitVSync();
418
419         if (notified)
420                 p.notify();
421
422         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
423                 if (i->m_animation.m_active)
424                         i->m_animation.tick(1);
425 }
426
427 void eWidgetDesktop::notify()
428 {
429         redrawComposition(1);
430 }
431
432 void eWidgetDesktop::clearVisibility(eWidget *widget)
433 {
434         widget->m_visible_with_childs = gRegion();
435         for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
436                 clearVisibility(*i);
437 }