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);
337 gPainter painter(m_screen.m_dc);
342 void eWidgetDesktop::setDC(gDC *dc)
345 if (m_comp_mode == cmBuffered)
346 redrawComposition(1);
349 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
357 m_timer = eTimer::create(m_mainloop);
358 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
360 if (m_require_redraw)
361 m_timer->start(0, 1);
364 void eWidgetDesktop::makeCompatiblePixmap(ePtr<gPixmap> &pm)
366 makeCompatiblePixmap(*(pm.operator->()));
369 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
371 if (m_comp_mode != cmImmediate)
374 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
377 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
381 ePtr<gPixmap> target_pixmap;
382 m_screen.m_dc->getPixmap(target_pixmap);
384 ASSERT(target_pixmap);
386 if (target_pixmap->surface && target_pixmap->surface->bpp > 8)
389 ePtr<gDC> pixmap_dc = new gDC(&pm);
390 gPainter pixmap_painter(pixmap_dc);
392 pixmap_painter.mergePalette(target_pixmap);
395 void eWidgetDesktop::setCompositionMode(int mode)
399 if (mode == cmBuffered)
400 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
401 createBufferForWidget(*i, 0);
403 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
404 for (int l = 0; l < MAX_LAYER; ++l)
405 removeBufferForWidget(*i, l);
408 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0)
410 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
411 m_screen.m_screen_size = size;
412 m_require_redraw = 0;
415 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
416 setCompositionMode(cmImmediate);
419 eWidgetDesktop::~eWidgetDesktop()
421 /* tell registered root windows that they no longer have a desktop. */
422 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); )
427 /* destroy all buffers */
428 setCompositionMode(-1);
431 void eWidgetDesktop::createBufferForWidget(eWidget *widget, int layer)
433 removeBufferForWidget(widget, layer);
435 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer[layer] = new eWidgetDesktopCompBuffer;
437 eDebug("create buffer for widget layer %d, %d x %d\n", layer, widget->size().width(), widget->size().height());
439 eRect bbox = eRect(widget->position(), widget->size());
440 comp->m_position = bbox.topLeft();
441 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
442 comp->m_screen_size = bbox.size();
443 /* TODO: configurable bit depth. */
445 /* clone palette. FIXME. */
446 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
447 pm->surface->clut.data = new gRGB[256];
448 pm->surface->clut.colors = 256;
449 pm->surface->clut.start = 0;
451 m_screen.m_dc->getPixmap(pm_screen);
453 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
455 comp->m_dc = new gDC(pm);
458 void eWidgetDesktop::removeBufferForWidget(eWidget *widget, int layer)
460 if (widget->m_comp_buffer[layer])
462 delete widget->m_comp_buffer[layer];
463 widget->m_comp_buffer[layer] = 0;
467 void eWidgetDesktop::redrawComposition(int notified)
469 if (m_comp_mode != cmBuffered)
472 ASSERT(m_screen.m_dc);
474 gPainter p(m_screen.m_dc);
475 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
476 p.setBackgroundColor(m_screen.m_background_color);
479 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
483 for (int layer = 0; layer < MAX_LAYER; ++layer)
486 if (!i->m_comp_buffer[layer])
488 i->m_comp_buffer[layer]->m_dc->getPixmap(pm);
489 p.blit(pm, i->m_comp_buffer[layer]->m_position, eRect(), gPixmap::blitAlphaBlend);
493 // flip activates on next vsync.
500 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
501 if (i->m_animation.m_active)
502 i->m_animation.tick(1);
505 void eWidgetDesktop::notify()
507 redrawComposition(1);
510 void eWidgetDesktop::clearVisibility(eWidget *widget)
512 widget->m_visible_with_childs = gRegion();
513 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
517 void eWidgetDesktop::resize(eSize size)
519 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
520 m_screen.m_screen_size = size;