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, int top)
10 assert(!root->m_desktop);
12 /* buffered mode paints back-to-front, while immediate mode is front-to-back. */
13 if (m_comp_mode == cmBuffered)
17 m_root.push_back(root);
19 m_root.push_front(root);
20 root->m_desktop = this;
22 /* the creation will be postponed. */
23 root->m_comp_buffer = 0;
26 void eWidgetDesktop::removeRootWidget(eWidget *root)
28 if (m_comp_mode == cmBuffered)
29 removeBufferForWidget(root);
34 int eWidgetDesktop::movedWidget(eWidget *root)
36 if ((m_comp_mode == cmBuffered) && (root->m_comp_buffer))
38 root->m_comp_buffer->m_position = root->position();
39 // redrawComposition(0);
46 void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible)
48 /* start with our clip region, clipped with the parent's */
49 if (widget->m_vis & eWidget::wVisShow)
51 widget->m_visible_region = widget->m_clip_region;
52 widget->m_visible_region.moveBy(widget->position());
53 widget->m_visible_region &= parent_visible; // in parent space!
55 if (!widget->isTransparent())
56 /* remove everything this widget will contain from parent's visible list, unless widget is transparent. */
57 parent_visible -= widget->m_visible_region; // will remove child regions too!
59 /* now prepare for recursing to childs */
60 widget->m_visible_region.moveBy(-widget->position()); // now in local space
62 widget->m_visible_region = gRegion();
64 widget->m_visible_with_childs = widget->m_visible_region;
66 /* add childs in reverse (Z) order - we're going from front-to-bottom here. */
67 ePtrList<eWidget>::iterator i(widget->m_childs.end());
71 if (i != widget->m_childs.end())
73 if (i->m_vis & eWidget::wVisShow)
74 calcWidgetClipRegion(*i, widget->m_visible_region);
78 if (i == widget->m_childs.begin())
84 void eWidgetDesktop::recalcClipRegions(eWidget *root)
86 if (m_comp_mode == cmImmediate)
88 gRegion background_before = m_screen.m_background_region;
90 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
92 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
94 if (!(i->m_vis & eWidget::wVisShow))
100 gRegion visible_before = i->m_visible_with_childs;
102 calcWidgetClipRegion(*i, m_screen.m_background_region);
104 gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
106 redraw.moveBy(i->position());
111 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
113 } else if (m_comp_mode == cmBuffered)
115 if (!root->m_vis & eWidget::wVisShow)
117 clearVisibility(root);
118 removeBufferForWidget(root);
121 if ((!root->m_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
122 createBufferForWidget(root);
124 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
126 gRegion visible_before = root->m_visible_with_childs;
128 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
130 gRegion visible_new = root->m_visible_with_childs - visible_before;
131 gRegion visible_lost = visible_before - root->m_visible_with_childs;
132 visible_new.moveBy(root->position());
133 visible_lost.moveBy(root->position());
135 /* this sucks, obviously. */
136 invalidate(visible_new);
137 invalidate(visible_lost);
139 calcWidgetClipRegion(root, comp->m_background_region);
143 void eWidgetDesktop::invalidate(const gRegion ®ion)
148 if (m_timer && !m_require_redraw)
149 m_timer->start(0, 1); // start singleshot redraw timer
151 m_require_redraw = 1;
153 if (m_comp_mode == cmImmediate)
154 m_screen.m_dirty_region |= region;
156 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
158 if (!(i->m_vis & eWidget::wVisShow))
161 eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
163 gRegion mregion = region;
164 comp->m_dirty_region |= mregion;
168 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
170 comp->m_background_color = col;
172 /* if there's something visible from the background, redraw it with the new color. */
173 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
175 /* todo: split out "setBackgroundColor / clear"... maybe? */
176 gPainter painter(comp->m_dc);
177 painter.resetClip(comp->m_background_region);
178 painter.setBackgroundColor(comp->m_background_color);
183 void eWidgetDesktop::setBackgroundColor(gRGB col)
185 setBackgroundColor(&m_screen, col);
187 if (m_comp_mode == cmBuffered)
188 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
189 setBackgroundColor(i->m_comp_buffer, col);
192 void eWidgetDesktop::setPalette(gPixmap &pm)
194 // if (m_comp_mode == cmImmediate)
196 ASSERT(m_screen.m_dc);
197 gPainter painter(m_screen.m_dc);
198 painter.setPalette(&pm);
201 if (m_comp_mode == cmBuffered)
203 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
205 ASSERT(i->m_comp_buffer->m_dc);
206 gPainter painter(i->m_comp_buffer->m_dc);
207 painter.setPalette(&pm);
212 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
214 comp->m_dirty_region &= comp->m_background_region;
216 gPainter painter(comp->m_dc);
218 painter.resetClip(comp->m_dirty_region);
219 painter.setBackgroundColor(comp->m_background_color);
223 comp->m_dirty_region = gRegion();
226 void eWidgetDesktop::paint()
228 m_require_redraw = 0;
230 /* walk all root windows. */
231 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
233 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
235 if (!(i->m_vis & eWidget::wVisShow))
239 gPainter painter(comp->m_dc);
240 painter.moveOffset(-comp->m_position);
241 i->doPaint(painter, comp->m_dirty_region);
242 painter.resetOffset();
245 if (m_comp_mode != cmImmediate)
246 paintBackground(comp);
249 if (m_comp_mode == cmImmediate)
250 paintBackground(&m_screen);
252 if (m_comp_mode == cmBuffered)
254 // redrawComposition(0);
258 void eWidgetDesktop::setDC(gDC *dc)
261 if (m_comp_mode == cmBuffered)
262 redrawComposition(1);
265 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
274 m_timer = new eTimer(m_mainloop);
275 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
277 if (m_require_redraw)
278 m_timer->start(0, 1);
281 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
283 if (m_comp_mode != cmImmediate)
286 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
289 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
293 ePtr<gDC> pixmap_dc = new gDC(&pm);
294 gPainter pixmap_painter(pixmap_dc);
296 ePtr<gPixmap> target_pixmap;
297 m_screen.m_dc->getPixmap(target_pixmap);
299 assert(target_pixmap);
301 pixmap_painter.mergePalette(target_pixmap);
304 void eWidgetDesktop::setCompositionMode(int mode)
308 if (mode == cmBuffered)
309 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
310 createBufferForWidget(*i);
312 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
313 removeBufferForWidget(*i);
316 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
318 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
319 m_screen.m_screen_size = size;
320 m_require_redraw = 0;
322 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
323 setCompositionMode(cmImmediate);
326 eWidgetDesktop::~eWidgetDesktop()
328 /* destroy all buffers */
329 setCompositionMode(-1);
332 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
334 removeBufferForWidget(widget);
336 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
338 eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
340 eRect bbox = eRect(widget->position(), widget->size());
341 comp->m_position = bbox.topLeft();
342 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
343 comp->m_screen_size = bbox.size();
344 /* TODO: configurable bit depth. */
346 /* clone palette. FIXME. */
347 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
348 pm->surface->clut.data = new gRGB[256];
349 pm->surface->clut.colors = 256;
350 pm->surface->clut.start = 0;
353 m_screen.m_dc->getPixmap(pm_screen);
355 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
357 comp->m_dc = new gDC(pm);
360 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
362 if (widget->m_comp_buffer)
364 delete widget->m_comp_buffer;
365 widget->m_comp_buffer = 0;
369 void eWidgetDesktop::redrawComposition(int notified)
371 if (m_comp_mode != cmBuffered)
374 assert(m_screen.m_dc);
376 gPainter p(m_screen.m_dc);
377 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
378 p.setBackgroundColor(m_screen.m_background_color);
381 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
386 ASSERT(i->m_comp_buffer);
387 i->m_comp_buffer->m_dc->getPixmap(pm);
388 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
391 // flip activates on next vsync.
398 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
399 if (i->m_animation.m_active)
400 i->m_animation.tick(1);
403 void eWidgetDesktop::notify()
405 redrawComposition(1);
408 void eWidgetDesktop::clearVisibility(eWidget *widget)
410 widget->m_visible_with_childs = gRegion();
411 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)