1 #include <lib/gui/ewidgetdesktop.h>
2 #include <lib/gui/ewidget.h>
3 #include <lib/base/ebase.h>
4 #include <lib/gdi/grc.h>
6 extern void dumpRegion(const gRegion ®ion);
8 void eWidgetDesktop::addRootWidget(eWidget *root)
10 ASSERT(!root->m_desktop);
13 /* buffered mode paints back-to-front, while immediate mode is front-to-back. */
14 if (m_comp_mode == cmBuffered)
17 ePtrList<eWidget>::iterator insert_position = m_root.begin();
21 if ((insert_position == m_root.end()) || (invert_sense ^ (insert_position->m_z_position < root->m_z_position)))
23 m_root.insert(insert_position, root);
29 root->m_desktop = this;
31 /* the creation will be postponed. */
32 for (int i = 0; i < MAX_LAYER; ++i)
33 root->m_comp_buffer[i] = 0;
36 void eWidgetDesktop::removeRootWidget(eWidget *root)
38 if (m_comp_mode == cmBuffered)
40 for (int i = 0; i < MAX_LAYER; ++i)
41 removeBufferForWidget(root, i);
47 int eWidgetDesktop::movedWidget(eWidget *root)
49 if (m_comp_mode != cmBuffered)
50 return -1; /* native move not supported */
52 for (int i = 0; i < MAX_LAYER; ++i)
54 if (root->m_comp_buffer[i])
55 root->m_comp_buffer[i]->m_position = root->position();
56 // redrawComposition(0);
59 return 0; /* native move ok */
62 void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible)
64 /* start with our clip region, clipped with the parent's */
65 if (widget->m_vis & eWidget::wVisShow)
67 widget->m_visible_region = widget->m_clip_region;
68 widget->m_visible_region.moveBy(widget->position());
69 widget->m_visible_region &= parent_visible; // in parent space!
71 if (!widget->isTransparent())
72 /* remove everything this widget will contain from parent's visible list, unless widget is transparent. */
73 parent_visible -= widget->m_visible_region; // will remove child regions too!
75 /* now prepare for recursing to childs */
76 widget->m_visible_region.moveBy(-widget->position()); // now in local space
78 widget->m_visible_region = gRegion();
80 widget->m_visible_with_childs = widget->m_visible_region;
82 /* add childs in reverse (Z) order - we're going from front-to-bottom here. */
83 ePtrList<eWidget>::iterator i(widget->m_childs.end());
87 if (i != widget->m_childs.end())
89 if (i->m_vis & eWidget::wVisShow)
90 calcWidgetClipRegion(*i, widget->m_visible_region);
94 if (i == widget->m_childs.begin())
100 void eWidgetDesktop::recalcClipRegions(eWidget *root)
102 if (m_comp_mode == cmImmediate)
104 gRegion background_before = m_screen.m_background_region;
106 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
108 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
110 if (!(i->m_vis & eWidget::wVisShow))
116 gRegion visible_before = i->m_visible_with_childs;
118 calcWidgetClipRegion(*i, m_screen.m_background_region);
120 gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
122 redraw.moveBy(i->position());
127 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
129 } else if (m_comp_mode == cmBuffered)
131 if (!root->m_vis & eWidget::wVisShow)
133 clearVisibility(root);
134 for (int i = 0; i < MAX_LAYER; ++i)
135 removeBufferForWidget(root, i);
139 for (int i = 0; i < MAX_LAYER; ++i)
141 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer[i];
143 /* TODO: layers might not be required to have the screen size, for memory reasons. */
144 if ((i == 0 && !comp) || (comp && (root->size() != comp->m_screen_size)))
145 createBufferForWidget(root, 0);
147 comp = root->m_comp_buffer[i]; /* it might have changed. */
150 continue; /* WAIT, don't we need to invalidate,whatever */
152 /* CHECKME: don't we need to recalculate everything? after all, our buffer has changed and is likely to be cleared */
153 gRegion visible_before = root->m_visible_with_childs;
155 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
157 gRegion visible_new = root->m_visible_with_childs - visible_before;
158 gRegion visible_lost = visible_before - root->m_visible_with_childs;
159 visible_new.moveBy(root->position());
160 visible_lost.moveBy(root->position());
162 invalidate(visible_new, root, i);
163 invalidate(visible_lost, root, i);
165 calcWidgetClipRegion(root, comp->m_background_region);
170 void eWidgetDesktop::invalidateWidgetLayer(const gRegion ®ion, const eWidget *widget, int layer)
172 if (m_comp_mode == cmImmediate)
177 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer[layer];
179 comp->m_dirty_region |= region;
182 void eWidgetDesktop::invalidateWidget(const gRegion ®ion, const eWidget *widget, int layer)
184 if (m_comp_mode == cmImmediate)
190 if (!(widget->m_vis & eWidget::wVisShow))
193 gRegion mregion = region;
195 for (int layer = 0; layer < MAX_LAYER; ++layer)
196 invalidateWidgetLayer(mregion, widget, layer);
198 invalidateWidgetLayer(mregion, widget, layer);
201 void eWidgetDesktop::invalidate(const gRegion ®ion, const eWidget *widget, int layer)
206 if (m_timer && !m_require_redraw)
207 m_timer->start(0, 1); // start singleshot redraw timer
209 m_require_redraw = 1;
211 if (m_comp_mode == cmImmediate)
213 /* in immediate mode, we don't care for widget and layer, we use the topmost. */
214 m_screen.m_dirty_region |= region;
218 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
219 invalidateWidget(region, i);
221 invalidateWidget(region, widget, layer);
225 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
227 comp->m_background_color = col;
229 /* if there's something visible from the background, redraw it with the new color. */
230 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
232 /* todo: split out "setBackgroundColor / clear"... maybe? */
233 gPainter painter(comp->m_dc);
234 painter.resetClip(comp->m_background_region);
235 painter.setBackgroundColor(comp->m_background_color);
240 void eWidgetDesktop::setBackgroundColor(gRGB col)
242 setBackgroundColor(&m_screen, col);
244 if (m_comp_mode == cmBuffered)
245 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
247 for (int l = 0; l < MAX_LAYER; ++l)
248 if (i->m_comp_buffer[l])
249 setBackgroundColor(i->m_comp_buffer[l], l ? gRGB(0, 0, 0, 0) : col); /* all layers above 0 will have a transparent background */
253 void eWidgetDesktop::setPalette(gPixmap &pm)
255 // if (m_comp_mode == cmImmediate)
257 ASSERT(m_screen.m_dc);
258 gPainter painter(m_screen.m_dc);
259 painter.setPalette(&pm);
262 if (m_comp_mode == cmBuffered)
264 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
266 for (int l = 0; l < MAX_LAYER; ++l)
268 if (!i->m_comp_buffer[l])
270 ASSERT(i->m_comp_buffer[l]->m_dc);
271 gPainter painter(i->m_comp_buffer[l]->m_dc);
272 painter.setPalette(&pm);
278 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
283 comp->m_dirty_region &= comp->m_background_region;
285 gPainter painter(comp->m_dc);
287 painter.resetClip(comp->m_dirty_region);
288 painter.setBackgroundColor(comp->m_background_color);
291 comp->m_dirty_region = gRegion();
295 void eWidgetDesktop::paintLayer(eWidget *widget, int layer)
297 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : widget->m_comp_buffer[layer];
298 if (m_comp_mode == cmImmediate)
302 gPainter painter(comp->m_dc);
303 painter.moveOffset(-comp->m_position);
304 widget->doPaint(painter, comp->m_dirty_region, layer);
305 painter.resetOffset();
308 void eWidgetDesktop::paint()
310 m_require_redraw = 0;
312 /* walk all root windows. */
313 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
316 if (!(i->m_vis & eWidget::wVisShow))
319 if (m_comp_mode == cmImmediate)
322 for (int l = 0; l < MAX_LAYER; ++l)
325 paintBackground(i->m_comp_buffer[l]);
329 if (m_comp_mode == cmImmediate)
330 paintBackground(&m_screen);
332 if (m_comp_mode == cmBuffered)
334 // redrawComposition(0);
338 void eWidgetDesktop::setDC(gDC *dc)
341 if (m_comp_mode == cmBuffered)
342 redrawComposition(1);
345 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
353 m_timer = eTimer::create(m_mainloop);
354 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
356 if (m_require_redraw)
357 m_timer->start(0, 1);
360 void eWidgetDesktop::makeCompatiblePixmap(ePtr<gPixmap> &pm)
362 makeCompatiblePixmap(*(pm.operator->()));
365 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
367 if (m_comp_mode != cmImmediate)
370 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
373 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
377 ePtr<gPixmap> target_pixmap;
378 m_screen.m_dc->getPixmap(target_pixmap);
380 ASSERT(target_pixmap);
382 if (target_pixmap->surface && target_pixmap->surface->bpp > 8)
385 ePtr<gDC> pixmap_dc = new gDC(&pm);
386 gPainter pixmap_painter(pixmap_dc);
388 pixmap_painter.mergePalette(target_pixmap);
391 void eWidgetDesktop::setCompositionMode(int mode)
395 if (mode == cmBuffered)
396 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
397 createBufferForWidget(*i, 0);
399 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
400 for (int l = 0; l < MAX_LAYER; ++l)
401 removeBufferForWidget(*i, l);
404 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0)
406 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
407 m_screen.m_screen_size = size;
408 m_require_redraw = 0;
411 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
412 setCompositionMode(cmImmediate);
415 eWidgetDesktop::~eWidgetDesktop()
417 /* tell registered root windows that they no longer have a desktop. */
418 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); )
423 /* destroy all buffers */
424 setCompositionMode(-1);
427 void eWidgetDesktop::createBufferForWidget(eWidget *widget, int layer)
429 removeBufferForWidget(widget, layer);
431 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer[layer] = new eWidgetDesktopCompBuffer;
433 eDebug("create buffer for widget layer %d, %d x %d\n", layer, widget->size().width(), widget->size().height());
435 eRect bbox = eRect(widget->position(), widget->size());
436 comp->m_position = bbox.topLeft();
437 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
438 comp->m_screen_size = bbox.size();
439 /* TODO: configurable bit depth. */
441 /* clone palette. FIXME. */
442 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
443 pm->surface->clut.data = new gRGB[256];
444 pm->surface->clut.colors = 256;
445 pm->surface->clut.start = 0;
447 m_screen.m_dc->getPixmap(pm_screen);
449 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
451 comp->m_dc = new gDC(pm);
454 void eWidgetDesktop::removeBufferForWidget(eWidget *widget, int layer)
456 if (widget->m_comp_buffer[layer])
458 delete widget->m_comp_buffer[layer];
459 widget->m_comp_buffer[layer] = 0;
463 void eWidgetDesktop::redrawComposition(int notified)
465 if (m_comp_mode != cmBuffered)
468 ASSERT(m_screen.m_dc);
470 gPainter p(m_screen.m_dc);
471 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
472 p.setBackgroundColor(m_screen.m_background_color);
475 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
479 for (int layer = 0; layer < MAX_LAYER; ++layer)
482 if (!i->m_comp_buffer[layer])
484 i->m_comp_buffer[layer]->m_dc->getPixmap(pm);
485 p.blit(pm, i->m_comp_buffer[layer]->m_position, eRect(), gPixmap::blitAlphaBlend);
489 // flip activates on next vsync.
496 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
497 if (i->m_animation.m_active)
498 i->m_animation.tick(1);
501 void eWidgetDesktop::notify()
503 redrawComposition(1);
506 void eWidgetDesktop::clearVisibility(eWidget *widget)
508 widget->m_visible_with_childs = gRegion();
509 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
513 void eWidgetDesktop::resize(eSize size)
515 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
516 m_screen.m_screen_size = size;