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);
73 void eWidgetDesktop::recalcClipRegions(eWidget *root)
75 if (m_comp_mode == cmImmediate)
77 gRegion background_before = m_screen.m_background_region;
79 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
81 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
83 if (!(i->m_vis & eWidget::wVisShow))
89 gRegion visible_before = i->m_visible_with_childs;
91 calcWidgetClipRegion(*i, m_screen.m_background_region);
93 gRegion redraw = (i->m_visible_with_childs - visible_before) | (visible_before - i->m_visible_with_childs);
95 redraw.moveBy(i->position());
100 gRegion redraw = (background_before - m_screen.m_background_region) | (m_screen.m_background_region - background_before);
102 } else if (m_comp_mode == cmBuffered)
104 if (!root->m_vis & eWidget::wVisShow)
106 clearVisibility(root);
107 removeBufferForWidget(root);
110 if ((!root->m_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
111 createBufferForWidget(root);
113 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
115 gRegion visible_before = root->m_visible_with_childs;
117 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
119 gRegion visible_new = root->m_visible_with_childs - visible_before;
120 gRegion visible_lost = visible_before - root->m_visible_with_childs;
121 visible_new.moveBy(root->position());
122 visible_lost.moveBy(root->position());
124 /* this sucks, obviously. */
125 invalidate(visible_new);
126 invalidate(visible_lost);
128 calcWidgetClipRegion(root, comp->m_background_region);
132 void eWidgetDesktop::invalidate(const gRegion ®ion)
137 if (m_timer && !m_require_redraw)
138 m_timer->start(0, 1); // start singleshot redraw timer
140 m_require_redraw = 1;
142 if (m_comp_mode == cmImmediate)
143 m_screen.m_dirty_region |= region;
145 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
147 if (!(i->m_vis & eWidget::wVisShow))
150 eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
152 gRegion mregion = region;
153 comp->m_dirty_region |= mregion;
157 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
159 comp->m_background_color = col;
161 /* if there's something visible from the background, redraw it with the new color. */
162 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
164 /* todo: split out "setBackgroundColor / clear"... maybe? */
165 gPainter painter(comp->m_dc);
166 painter.resetClip(comp->m_background_region);
167 painter.setBackgroundColor(comp->m_background_color);
172 void eWidgetDesktop::setBackgroundColor(gRGB col)
174 setBackgroundColor(&m_screen, col);
176 if (m_comp_mode == cmBuffered)
177 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
178 setBackgroundColor(i->m_comp_buffer, col);
181 void eWidgetDesktop::setPalette(gPixmap &pm)
183 // if (m_comp_mode == cmImmediate)
185 ASSERT(m_screen.m_dc);
186 gPainter painter(m_screen.m_dc);
187 painter.setPalette(&pm);
190 if (m_comp_mode == cmBuffered)
192 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
194 ASSERT(i->m_comp_buffer->m_dc);
195 gPainter painter(i->m_comp_buffer->m_dc);
196 painter.setPalette(&pm);
201 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
203 comp->m_dirty_region &= comp->m_background_region;
205 gPainter painter(comp->m_dc);
207 painter.resetClip(comp->m_dirty_region);
208 painter.setBackgroundColor(comp->m_background_color);
212 comp->m_dirty_region = gRegion();
215 void eWidgetDesktop::paint()
217 m_require_redraw = 0;
219 /* walk all root windows. */
220 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
222 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
224 if (!(i->m_vis & eWidget::wVisShow))
228 gPainter painter(comp->m_dc);
229 painter.moveOffset(-comp->m_position);
230 i->doPaint(painter, comp->m_dirty_region);
231 painter.resetOffset();
234 if (m_comp_mode != cmImmediate)
235 paintBackground(comp);
238 if (m_comp_mode == cmImmediate)
239 paintBackground(&m_screen);
241 if (m_comp_mode == cmBuffered)
243 // redrawComposition(0);
247 void eWidgetDesktop::setDC(gDC *dc)
250 if (m_comp_mode == cmBuffered)
251 redrawComposition(1);
254 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
263 m_timer = new eTimer(m_mainloop);
264 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
266 if (m_require_redraw)
267 m_timer->start(0, 1);
270 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
272 if (m_comp_mode != cmImmediate)
275 // eDebug("widgetDesktop: make compatible pixmap of %p", &pm);
278 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
282 ePtr<gDC> pixmap_dc = new gDC(&pm);
283 gPainter pixmap_painter(pixmap_dc);
285 ePtr<gPixmap> target_pixmap;
286 m_screen.m_dc->getPixmap(target_pixmap);
288 assert(target_pixmap);
290 pixmap_painter.mergePalette(target_pixmap);
293 void eWidgetDesktop::setCompositionMode(int mode)
297 if (mode == cmBuffered)
298 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
299 createBufferForWidget(*i);
301 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
302 removeBufferForWidget(*i);
305 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
307 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
308 m_screen.m_screen_size = size;
309 m_require_redraw = 0;
311 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
312 setCompositionMode(cmImmediate);
315 eWidgetDesktop::~eWidgetDesktop()
317 /* destroy all buffers */
318 setCompositionMode(-1);
321 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
323 removeBufferForWidget(widget);
325 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
327 eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
329 eRect bbox = eRect(widget->position(), widget->size());
330 comp->m_position = bbox.topLeft();
331 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
332 comp->m_screen_size = bbox.size();
333 /* TODO: configurable bit depth. */
335 /* clone palette. FIXME. */
336 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
337 pm->surface->clut.data = new gRGB[256];
338 pm->surface->clut.colors = 256;
339 pm->surface->clut.start = 0;
342 m_screen.m_dc->getPixmap(pm_screen);
344 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
346 comp->m_dc = new gDC(pm);
349 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
351 if (widget->m_comp_buffer)
353 delete widget->m_comp_buffer;
354 widget->m_comp_buffer = 0;
358 void eWidgetDesktop::redrawComposition(int notified)
360 if (m_comp_mode != cmBuffered)
363 assert(m_screen.m_dc);
365 gPainter p(m_screen.m_dc);
366 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
367 p.setBackgroundColor(m_screen.m_background_color);
370 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
375 ASSERT(i->m_comp_buffer);
376 i->m_comp_buffer->m_dc->getPixmap(pm);
377 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
380 // flip activates on next vsync.
387 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
388 if (i->m_animation.m_active)
389 i->m_animation.tick(1);
392 void eWidgetDesktop::notify()
394 redrawComposition(1);
397 void eWidgetDesktop::clearVisibility(eWidget *widget)
399 widget->m_visible_with_childs = gRegion();
400 for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)