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 root->m_comp_buffer = 0;
35 void eWidgetDesktop::removeRootWidget(eWidget *root)
37 if (m_comp_mode == cmBuffered)
38 removeBufferForWidget(root);
43 int eWidgetDesktop::movedWidget(eWidget *root)
45 if ((m_comp_mode == cmBuffered) && (root->m_comp_buffer))
47 root->m_comp_buffer->m_position = root->position();
48 // redrawComposition(0);
55 void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible)
57 /* start with our clip region, clipped with the parent's */
58 if (widget->m_vis & eWidget::wVisShow)
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!
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!
68 /* now prepare for recursing to childs */
69 widget->m_visible_region.moveBy(-widget->position()); // now in local space
71 widget->m_visible_region = gRegion();
73 widget->m_visible_with_childs = widget->m_visible_region;
75 /* add childs in reverse (Z) order - we're going from front-to-bottom here. */
76 ePtrList<eWidget>::iterator i(widget->m_childs.end());
80 if (i != widget->m_childs.end())
82 if (i->m_vis & eWidget::wVisShow)
83 calcWidgetClipRegion(*i, widget->m_visible_region);
87 if (i == widget->m_childs.begin())
93 void eWidgetDesktop::recalcClipRegions(eWidget *root)
95 if (m_comp_mode == cmImmediate)
97 gRegion background_before = m_screen.m_background_region;
99 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
101 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
103 if (!(i->m_vis & eWidget::wVisShow))
109 gRegion visible_before = i->m_visible_with_childs;
111 calcWidgetClipRegion(*i, m_screen.m_background_region);
113 gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
115 redraw.moveBy(i->position());
120 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
122 } else if (m_comp_mode == cmBuffered)
124 if (!root->m_vis & eWidget::wVisShow)
126 clearVisibility(root);
127 removeBufferForWidget(root);
130 if ((!root->m_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
131 createBufferForWidget(root);
133 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
135 gRegion visible_before = root->m_visible_with_childs;
137 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
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());
144 /* this sucks, obviously. */
145 invalidate(visible_new);
146 invalidate(visible_lost);
148 calcWidgetClipRegion(root, comp->m_background_region);
152 void eWidgetDesktop::invalidate(const gRegion ®ion)
157 if (m_timer && !m_require_redraw)
158 m_timer->start(0, 1); // start singleshot redraw timer
160 m_require_redraw = 1;
162 if (m_comp_mode == cmImmediate)
163 m_screen.m_dirty_region |= region;
165 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
167 if (!(i->m_vis & eWidget::wVisShow))
170 eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
172 gRegion mregion = region;
173 comp->m_dirty_region |= mregion;
177 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
179 comp->m_background_color = col;
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())
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);
192 void eWidgetDesktop::setBackgroundColor(gRGB col)
194 setBackgroundColor(&m_screen, col);
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);
201 void eWidgetDesktop::setPalette(gPixmap &pm)
203 // if (m_comp_mode == cmImmediate)
205 ASSERT(m_screen.m_dc);
206 gPainter painter(m_screen.m_dc);
207 painter.setPalette(&pm);
210 if (m_comp_mode == cmBuffered)
212 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
214 ASSERT(i->m_comp_buffer->m_dc);
215 gPainter painter(i->m_comp_buffer->m_dc);
216 painter.setPalette(&pm);
221 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
223 comp->m_dirty_region &= comp->m_background_region;
225 gPainter painter(comp->m_dc);
227 painter.resetClip(comp->m_dirty_region);
228 painter.setBackgroundColor(comp->m_background_color);
232 comp->m_dirty_region = gRegion();
235 void eWidgetDesktop::paint()
237 m_require_redraw = 0;
239 /* walk all root windows. */
240 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
242 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
244 if (!(i->m_vis & eWidget::wVisShow))
248 gPainter painter(comp->m_dc);
249 painter.moveOffset(-comp->m_position);
250 i->doPaint(painter, comp->m_dirty_region);
251 painter.resetOffset();
254 if (m_comp_mode != cmImmediate)
255 paintBackground(comp);
258 if (m_comp_mode == cmImmediate)
259 paintBackground(&m_screen);
261 if (m_comp_mode == cmBuffered)
263 // redrawComposition(0);
267 void eWidgetDesktop::setDC(gDC *dc)
270 if (m_comp_mode == cmBuffered)
271 redrawComposition(1);
274 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
283 m_timer = new eTimer(m_mainloop);
284 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
286 if (m_require_redraw)
287 m_timer->start(0, 1);
290 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
292 if (m_comp_mode != cmImmediate)
295 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
298 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
302 ePtr<gDC> pixmap_dc = new gDC(&pm);
303 gPainter pixmap_painter(pixmap_dc);
305 ePtr<gPixmap> target_pixmap;
306 m_screen.m_dc->getPixmap(target_pixmap);
308 assert(target_pixmap);
310 pixmap_painter.mergePalette(target_pixmap);
313 void eWidgetDesktop::setCompositionMode(int mode)
317 if (mode == cmBuffered)
318 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
319 createBufferForWidget(*i);
321 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
322 removeBufferForWidget(*i);
325 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
327 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
328 m_screen.m_screen_size = size;
329 m_require_redraw = 0;
331 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
332 setCompositionMode(cmImmediate);
335 eWidgetDesktop::~eWidgetDesktop()
337 /* tell registered root windows that they no longer have a desktop. */
338 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); )
343 /* destroy all buffers */
344 setCompositionMode(-1);
347 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
349 removeBufferForWidget(widget);
351 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
353 eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
355 eRect bbox = eRect(widget->position(), widget->size());
356 comp->m_position = bbox.topLeft();
357 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
358 comp->m_screen_size = bbox.size();
359 /* TODO: configurable bit depth. */
361 /* clone palette. FIXME. */
362 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
363 pm->surface->clut.data = new gRGB[256];
364 pm->surface->clut.colors = 256;
365 pm->surface->clut.start = 0;
368 m_screen.m_dc->getPixmap(pm_screen);
370 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
372 comp->m_dc = new gDC(pm);
375 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
377 if (widget->m_comp_buffer)
379 delete widget->m_comp_buffer;
380 widget->m_comp_buffer = 0;
384 void eWidgetDesktop::redrawComposition(int notified)
386 if (m_comp_mode != cmBuffered)
389 assert(m_screen.m_dc);
391 gPainter p(m_screen.m_dc);
392 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
393 p.setBackgroundColor(m_screen.m_background_color);
396 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
401 ASSERT(i->m_comp_buffer);
402 i->m_comp_buffer->m_dc->getPixmap(pm);
403 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
406 // flip activates on next vsync.
413 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
414 if (i->m_animation.m_active)
415 i->m_animation.tick(1);
418 void eWidgetDesktop::notify()
420 redrawComposition(1);
423 void eWidgetDesktop::clearVisibility(eWidget *widget)
425 widget->m_visible_with_childs = gRegion();
426 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)