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. */
149 /* CHECKME: don't we need to recalculate everything? after all, our buffer has changed and is likely to be cleared */
150 gRegion visible_before = root->m_visible_with_childs;
152 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
154 gRegion visible_new = root->m_visible_with_childs - visible_before;
155 gRegion visible_lost = visible_before - root->m_visible_with_childs;
156 visible_new.moveBy(root->position());
157 visible_lost.moveBy(root->position());
159 invalidate(visible_new, root, i);
160 invalidate(visible_lost, root, i);
162 calcWidgetClipRegion(root, comp->m_background_region);
167 void eWidgetDesktop::invalidateWidgetLayer(const gRegion ®ion, const eWidget *widget, int layer)
169 if (m_comp_mode == cmImmediate)
174 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer[layer];
176 comp->m_dirty_region |= region;
179 void eWidgetDesktop::invalidateWidget(const gRegion ®ion, const eWidget *widget, int layer)
181 if (m_comp_mode == cmImmediate)
187 if (!(widget->m_vis & eWidget::wVisShow))
190 gRegion mregion = region;
192 for (int layer = 0; layer < MAX_LAYER; ++layer)
193 invalidateWidgetLayer(mregion, widget, layer);
195 invalidateWidgetLayer(mregion, widget, layer);
198 void eWidgetDesktop::invalidate(const gRegion ®ion, const eWidget *widget, int layer)
203 if (m_timer && !m_require_redraw)
204 m_timer->start(0, 1); // start singleshot redraw timer
206 m_require_redraw = 1;
208 if (m_comp_mode == cmImmediate)
210 /* in immediate mode, we don't care for widget and layer, we use the topmost. */
211 m_screen.m_dirty_region |= region;
215 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
216 invalidateWidget(region, i);
218 invalidateWidget(region, widget, layer);
222 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
224 comp->m_background_color = col;
226 /* if there's something visible from the background, redraw it with the new color. */
227 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
229 /* todo: split out "setBackgroundColor / clear"... maybe? */
230 gPainter painter(comp->m_dc);
231 painter.resetClip(comp->m_background_region);
232 painter.setBackgroundColor(comp->m_background_color);
237 void eWidgetDesktop::setBackgroundColor(gRGB col)
239 setBackgroundColor(&m_screen, col);
241 if (m_comp_mode == cmBuffered)
242 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
244 for (int l = 0; l < MAX_LAYER; ++l)
245 if (i->m_comp_buffer[l])
246 setBackgroundColor(i->m_comp_buffer[l], l ? gRGB(0, 0, 0, 0) : col); /* all layers above 0 will have a transparent background */
250 void eWidgetDesktop::setPalette(gPixmap &pm)
252 // if (m_comp_mode == cmImmediate)
254 ASSERT(m_screen.m_dc);
255 gPainter painter(m_screen.m_dc);
256 painter.setPalette(&pm);
259 if (m_comp_mode == cmBuffered)
261 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
263 for (int l = 0; l < MAX_LAYER; ++l)
265 if (!i->m_comp_buffer[l])
267 ASSERT(i->m_comp_buffer[l]->m_dc);
268 gPainter painter(i->m_comp_buffer[l]->m_dc);
269 painter.setPalette(&pm);
275 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
280 comp->m_dirty_region &= comp->m_background_region;
282 gPainter painter(comp->m_dc);
284 painter.resetClip(comp->m_dirty_region);
285 painter.setBackgroundColor(comp->m_background_color);
288 comp->m_dirty_region = gRegion();
292 void eWidgetDesktop::paintLayer(eWidget *widget, int layer)
294 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : widget->m_comp_buffer[layer];
295 if (m_comp_mode == cmImmediate)
299 gPainter painter(comp->m_dc);
300 painter.moveOffset(-comp->m_position);
301 widget->doPaint(painter, comp->m_dirty_region, layer);
302 painter.resetOffset();
305 void eWidgetDesktop::paint()
307 m_require_redraw = 0;
309 /* walk all root windows. */
310 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
313 if (!(i->m_vis & eWidget::wVisShow))
316 if (m_comp_mode == cmImmediate)
319 for (int l = 0; l < MAX_LAYER; ++l)
322 paintBackground(i->m_comp_buffer[l]);
326 if (m_comp_mode == cmImmediate)
327 paintBackground(&m_screen);
329 if (m_comp_mode == cmBuffered)
331 // redrawComposition(0);
335 void eWidgetDesktop::setDC(gDC *dc)
338 if (m_comp_mode == cmBuffered)
339 redrawComposition(1);
342 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
350 m_timer = eTimer::create(m_mainloop);
351 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
353 if (m_require_redraw)
354 m_timer->start(0, 1);
357 void eWidgetDesktop::makeCompatiblePixmap(ePtr<gPixmap> &pm)
359 makeCompatiblePixmap(*(pm.operator->()));
362 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
364 if (m_comp_mode != cmImmediate)
367 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
370 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
374 ePtr<gPixmap> target_pixmap;
375 m_screen.m_dc->getPixmap(target_pixmap);
377 assert(target_pixmap);
379 if (target_pixmap->surface && target_pixmap->surface->bpp > 8)
382 ePtr<gDC> pixmap_dc = new gDC(&pm);
383 gPainter pixmap_painter(pixmap_dc);
385 pixmap_painter.mergePalette(target_pixmap);
388 void eWidgetDesktop::setCompositionMode(int mode)
392 if (mode == cmBuffered)
393 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
394 createBufferForWidget(*i, 0);
396 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
397 for (int l = 0; l < MAX_LAYER; ++l)
398 removeBufferForWidget(*i, l);
401 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0)
403 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
404 m_screen.m_screen_size = size;
405 m_require_redraw = 0;
408 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
409 setCompositionMode(cmImmediate);
412 eWidgetDesktop::~eWidgetDesktop()
414 /* tell registered root windows that they no longer have a desktop. */
415 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); )
420 /* destroy all buffers */
421 setCompositionMode(-1);
424 void eWidgetDesktop::createBufferForWidget(eWidget *widget, int layer)
426 removeBufferForWidget(widget, layer);
428 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer[layer] = new eWidgetDesktopCompBuffer;
430 eDebug("create buffer for widget layer %d, %d x %d\n", layer, widget->size().width(), widget->size().height());
432 eRect bbox = eRect(widget->position(), widget->size());
433 comp->m_position = bbox.topLeft();
434 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
435 comp->m_screen_size = bbox.size();
436 /* TODO: configurable bit depth. */
438 /* clone palette. FIXME. */
439 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
440 pm->surface->clut.data = new gRGB[256];
441 pm->surface->clut.colors = 256;
442 pm->surface->clut.start = 0;
444 m_screen.m_dc->getPixmap(pm_screen);
446 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
448 comp->m_dc = new gDC(pm);
451 void eWidgetDesktop::removeBufferForWidget(eWidget *widget, int layer)
453 if (widget->m_comp_buffer[layer])
455 delete widget->m_comp_buffer[layer];
456 widget->m_comp_buffer[layer] = 0;
460 void eWidgetDesktop::redrawComposition(int notified)
462 if (m_comp_mode != cmBuffered)
465 assert(m_screen.m_dc);
467 gPainter p(m_screen.m_dc);
468 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
469 p.setBackgroundColor(m_screen.m_background_color);
472 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
476 for (int layer = 0; layer < MAX_LAYER; ++layer)
479 if (!i->m_comp_buffer[layer])
481 i->m_comp_buffer[layer]->m_dc->getPixmap(pm);
482 p.blit(pm, i->m_comp_buffer[layer]->m_position, eRect(), gPixmap::blitAlphaBlend);
486 // flip activates on next vsync.
493 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
494 if (i->m_animation.m_active)
495 i->m_animation.tick(1);
498 void eWidgetDesktop::notify()
500 redrawComposition(1);
503 void eWidgetDesktop::clearVisibility(eWidget *widget)
505 widget->m_visible_with_childs = gRegion();
506 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
510 void eWidgetDesktop::resize(eSize size)
512 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
513 m_screen.m_screen_size = size;