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!
54 /* TODO: check transparency here! */
56 /* remove everything this widget will contain from parent's visible list */
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 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
67 if (i->m_vis & eWidget::wVisShow)
68 calcWidgetClipRegion(*i, widget->m_visible_region);
71 void eWidgetDesktop::recalcClipRegions(eWidget *root)
73 if (m_comp_mode == cmImmediate)
75 gRegion background_before = m_screen.m_background_region;
77 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
79 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
81 if (!(i->m_vis & eWidget::wVisShow))
84 gRegion visible_before = i->m_visible_with_childs;
86 calcWidgetClipRegion(*i, m_screen.m_background_region);
88 gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
90 redraw.moveBy(i->position());
95 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
99 if (!root->m_vis & eWidget::wVisShow)
101 removeBufferForWidget(root);
104 if ((!root->m_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
105 createBufferForWidget(root);
107 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
109 gRegion visible_before = root->m_visible_with_childs;
111 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
113 gRegion visible_new = root->m_visible_with_childs - visible_before;
114 gRegion visible_lost = visible_before - root->m_visible_with_childs;
115 visible_new.moveBy(root->position());
116 visible_lost.moveBy(root->position());
118 /* this sucks, obviously. */
119 invalidate(visible_new);
120 invalidate(visible_lost);
122 calcWidgetClipRegion(root, comp->m_background_region);
126 void eWidgetDesktop::invalidate(const gRegion ®ion)
131 if (m_timer && !m_require_redraw)
132 m_timer->start(0, 1); // start singleshot redraw timer
134 m_require_redraw = 1;
136 if (m_comp_mode == cmImmediate)
137 m_screen.m_dirty_region |= region;
139 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
141 if (!(i->m_vis & eWidget::wVisShow))
144 eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
146 gRegion mregion = region;
147 comp->m_dirty_region |= mregion;
151 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
153 comp->m_background_color = col;
155 /* if there's something visible from the background, redraw it with the new color. */
156 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
158 /* todo: split out "setBackgroundColor / clear"... maybe? */
159 gPainter painter(comp->m_dc);
160 painter.resetClip(comp->m_background_region);
161 painter.setBackgroundColor(comp->m_background_color);
166 void eWidgetDesktop::setBackgroundColor(gRGB col)
168 setBackgroundColor(&m_screen, col);
170 if (m_comp_mode == cmBuffered)
171 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
172 setBackgroundColor(i->m_comp_buffer, col);
175 void eWidgetDesktop::setPalette(gPixmap &pm)
177 // if (m_comp_mode == cmImmediate)
179 ASSERT(m_screen.m_dc);
180 gPainter painter(m_screen.m_dc);
181 painter.setPalette(&pm);
184 if (m_comp_mode == cmBuffered)
186 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
188 ASSERT(i->m_comp_buffer->m_dc);
189 gPainter painter(i->m_comp_buffer->m_dc);
190 painter.setPalette(&pm);
195 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
197 comp->m_dirty_region &= comp->m_background_region;
199 gPainter painter(comp->m_dc);
201 painter.resetClip(comp->m_dirty_region);
202 painter.setBackgroundColor(comp->m_background_color);
206 comp->m_dirty_region = gRegion();
209 void eWidgetDesktop::paint()
211 m_require_redraw = 0;
213 /* walk all root windows. */
214 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
216 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
218 if (!(i->m_vis & eWidget::wVisShow))
222 gPainter painter(comp->m_dc);
223 painter.moveOffset(-comp->m_position);
224 i->doPaint(painter, comp->m_dirty_region);
225 painter.resetOffset();
228 if (m_comp_mode != cmImmediate)
229 paintBackground(comp);
232 if (m_comp_mode == cmImmediate)
233 paintBackground(&m_screen);
235 if (m_comp_mode == cmBuffered)
237 // redrawComposition(0);
241 void eWidgetDesktop::setDC(gDC *dc)
244 if (m_comp_mode == cmBuffered)
245 redrawComposition(1);
248 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
257 m_timer = new eTimer(m_mainloop);
258 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
260 if (m_require_redraw)
261 m_timer->start(0, 1);
264 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
266 if (m_comp_mode != cmImmediate)
269 eDebug("widgetDesktop: make compatible pixmap of %p\n", &pm);
272 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
276 ePtr<gDC> pixmap_dc = new gDC(&pm);
277 gPainter pixmap_painter(pixmap_dc);
279 ePtr<gPixmap> target_pixmap;
280 m_screen.m_dc->getPixmap(target_pixmap);
282 assert(target_pixmap);
284 pixmap_painter.mergePalette(target_pixmap);
287 void eWidgetDesktop::setCompositionMode(int mode)
291 if (mode == cmBuffered)
292 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
293 createBufferForWidget(*i);
295 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
296 removeBufferForWidget(*i);
299 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
301 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
302 m_screen.m_screen_size = size;
303 m_require_redraw = 0;
305 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
306 setCompositionMode(cmImmediate);
309 eWidgetDesktop::~eWidgetDesktop()
311 /* destroy all buffers */
312 setCompositionMode(-1);
315 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
317 removeBufferForWidget(widget);
319 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
321 eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
323 eRect bbox = eRect(widget->position(), widget->size());
324 comp->m_position = bbox.topLeft();
325 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
326 comp->m_screen_size = bbox.size();
327 /* TODO: configurable bit depth. */
329 /* clone palette. FIXME. */
330 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
331 pm->surface->clut.data = new gRGB[256];
332 pm->surface->clut.colors = 256;
333 pm->surface->clut.start = 0;
336 m_screen.m_dc->getPixmap(pm_screen);
338 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
340 comp->m_dc = new gDC(pm);
343 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
345 if (widget->m_comp_buffer)
347 delete widget->m_comp_buffer;
348 widget->m_comp_buffer = 0;
352 void eWidgetDesktop::redrawComposition(int notified)
354 if (m_comp_mode != cmBuffered)
357 assert(m_screen.m_dc);
359 gPainter p(m_screen.m_dc);
360 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
361 p.setBackgroundColor(m_screen.m_background_color);
364 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
369 ASSERT(i->m_comp_buffer);
370 i->m_comp_buffer->m_dc->getPixmap(pm);
371 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
374 // flip activates on next vsync.
381 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
382 if (i->m_animation.m_active)
383 i->m_animation.tick(1);
386 void eWidgetDesktop::notify()
388 redrawComposition(1);