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();
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_comp_buffer) || (root->size() != root->m_comp_buffer->m_screen_size))
100 createBufferForWidget(root);
102 eWidgetDesktopCompBuffer *comp = root->m_comp_buffer;
104 gRegion visible_before = root->m_visible_with_childs;
106 comp->m_background_region = gRegion(eRect(comp->m_position, comp->m_screen_size));
108 gRegion visible_new = root->m_visible_with_childs - visible_before;
109 gRegion visible_lost = visible_before - root->m_visible_with_childs;
110 visible_new.moveBy(root->position());
111 visible_lost.moveBy(root->position());
113 /* this sucks, obviously. */
114 invalidate(visible_new);
115 invalidate(visible_lost);
117 calcWidgetClipRegion(root, comp->m_background_region);
121 void eWidgetDesktop::invalidate(const gRegion ®ion)
126 if (m_timer && !m_require_redraw)
127 m_timer->start(0, 1); // start singleshot redraw timer
129 m_require_redraw = 1;
131 if (m_comp_mode == cmImmediate)
132 m_screen.m_dirty_region |= region;
134 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
136 if (!(i->m_vis & eWidget::wVisShow))
139 eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
141 gRegion mregion = region;
142 comp->m_dirty_region |= mregion;
146 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
148 comp->m_background_color = col;
150 /* if there's something visible from the background, redraw it with the new color. */
151 if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
153 /* todo: split out "setBackgroundColor / clear"... maybe? */
154 gPainter painter(comp->m_dc);
155 painter.resetClip(comp->m_background_region);
156 painter.setBackgroundColor(comp->m_background_color);
161 void eWidgetDesktop::setBackgroundColor(gRGB col)
163 setBackgroundColor(&m_screen, col);
165 if (m_comp_mode == cmBuffered)
166 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
167 setBackgroundColor(i->m_comp_buffer, col);
170 void eWidgetDesktop::setPalette(gPixmap &pm)
172 // if (m_comp_mode == cmImmediate)
174 ASSERT(m_screen.m_dc);
175 gPainter painter(m_screen.m_dc);
176 painter.setPalette(&pm);
179 if (m_comp_mode == cmBuffered)
181 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
183 ASSERT(i->m_comp_buffer->m_dc);
184 gPainter painter(i->m_comp_buffer->m_dc);
185 painter.setPalette(&pm);
190 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
192 comp->m_dirty_region &= comp->m_background_region;
194 gPainter painter(comp->m_dc);
196 painter.resetClip(comp->m_dirty_region);
197 painter.setBackgroundColor(comp->m_background_color);
201 comp->m_dirty_region = gRegion();
204 void eWidgetDesktop::paint()
207 m_require_redraw = 0;
209 /* walk all root windows. */
210 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
212 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
214 if (!(i->m_vis & eWidget::wVisShow))
218 gPainter painter(comp->m_dc);
219 painter.moveOffset(-comp->m_position);
220 i->doPaint(painter, comp->m_dirty_region);
221 painter.resetOffset();
224 if (m_comp_mode != cmImmediate)
225 paintBackground(comp);
228 if (m_comp_mode == cmImmediate)
229 paintBackground(&m_screen);
231 if (m_comp_mode == cmBuffered)
233 eDebug("redraw composition");
234 redrawComposition(0);
238 void eWidgetDesktop::setDC(gDC *dc)
241 if (m_comp_mode == cmBuffered)
242 redrawComposition(1);
245 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
254 m_timer = new eTimer(m_mainloop);
255 CONNECT(m_timer->timeout, eWidgetDesktop::paint);
257 if (m_require_redraw)
258 m_timer->start(0, 1);
261 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
263 if (m_comp_mode != cmImmediate)
266 eDebug("widgetDesktop: make compatible pixmap of %p\n", &pm);
269 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
273 ePtr<gDC> pixmap_dc = new gDC(&pm);
274 gPainter pixmap_painter(pixmap_dc);
276 ePtr<gPixmap> target_pixmap;
277 m_screen.m_dc->getPixmap(target_pixmap);
279 assert(target_pixmap);
281 pixmap_painter.mergePalette(target_pixmap);
284 void eWidgetDesktop::setCompositionMode(int mode)
288 if (mode == cmBuffered)
289 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
290 createBufferForWidget(*i);
292 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
293 removeBufferForWidget(*i);
296 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
298 m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
299 m_screen.m_screen_size = size;
300 m_require_redraw = 0;
302 CONNECT(gRC::getInstance()->notify, eWidgetDesktop::notify);
303 setCompositionMode(cmImmediate);
306 eWidgetDesktop::~eWidgetDesktop()
308 /* destroy all buffers */
309 setCompositionMode(-1);
312 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
314 removeBufferForWidget(widget);
316 eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
318 eDebug("create buffer for widget, %d x %d\n", widget->size().width(), widget->size().height());
320 eRect bbox = eRect(widget->position(), widget->size());
321 comp->m_position = bbox.topLeft();
322 comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
323 comp->m_screen_size = bbox.size();
324 /* TODO: configurable bit depth. */
326 /* clone palette. FIXME. */
327 ePtr<gPixmap> pm = new gPixmap(comp->m_screen_size, 32, 1), pm_screen;
328 pm->surface->clut.data = new gRGB[256];
329 pm->surface->clut.colors = 256;
330 pm->surface->clut.start = 0;
333 m_screen.m_dc->getPixmap(pm_screen);
335 memcpy(pm->surface->clut.data, pm_screen->surface->clut.data, 256 * sizeof(gRGB));
337 comp->m_dc = new gDC(pm);
340 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
342 if (widget->m_comp_buffer)
344 delete widget->m_comp_buffer;
345 widget->m_comp_buffer = 0;
349 void eWidgetDesktop::redrawComposition(int notified)
351 if (m_comp_mode != cmBuffered)
354 assert(m_screen.m_dc);
356 gPainter p(m_screen.m_dc);
357 p.resetClip(eRect(ePoint(0, 0), m_screen.m_screen_size));
358 p.setBackgroundColor(m_screen.m_background_color);
361 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
366 ASSERT(i->m_comp_buffer);
367 i->m_comp_buffer->m_dc->getPixmap(pm);
368 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaBlend);
371 // flip activates on next vsync.
378 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
379 if (i->m_animation.m_active)
380 i->m_animation.tick(1);
383 void eWidgetDesktop::notify()
385 redrawComposition(1);