d4a02010e08034e9a2b073698a071620564731d5
[enigma2.git] / lib / gui / ewidgetdesktop.cpp
1 #include <lib/gui/ewidgetdesktop.h>
2 #include <lib/gui/ewidget.h>
3 #include <lib/base/ebase.h>
4
5 void eWidgetDesktop::addRootWidget(eWidget *root, int top)
6 {
7         assert(!root->m_desktop);
8         if (!top)
9                 m_root.push_back(root);
10         else
11                 m_root.push_front(root);
12         root->m_desktop = this;
13
14                 /* the creation will be postponed. */
15         root->m_comp_buffer = 0;
16 }
17
18 void eWidgetDesktop::removeRootWidget(eWidget *root)
19 {
20         if (m_comp_mode == cmBuffered)
21                 removeBufferForWidget(root);
22
23         m_root.remove(root);
24 }
25
26 void eWidgetDesktop::calcWidgetClipRegion(struct eWidgetDesktopCompBuffer *comp, eWidget *widget, gRegion &parent_visible)
27 {
28                 /* start with our clip region, clipped with the parent's */
29         if (widget->m_vis & eWidget::wVisShow)
30         {
31                 widget->m_visible_region = widget->m_clip_region;
32                 widget->m_visible_region.moveBy(widget->position() - comp->m_position);
33                 widget->m_visible_region &= parent_visible; // in parent space!
34                         /* TODO: check transparency here! */
35
36                         /* remove everything this widget will contain from parent's visible list */
37                 parent_visible -= widget->m_visible_region; // will remove child regions too!
38
39                         /* now prepare for recursing to childs */
40                 widget->m_visible_region.moveBy(-widget->position());            // now in local space
41
42         } else
43                 widget->m_visible_region = gRegion();
44
45         widget->m_visible_with_childs = widget->m_visible_region;
46         
47         for (ePtrList<eWidget>::iterator i(widget->m_childs.begin()); i != widget->m_childs.end(); ++i)
48                 calcWidgetClipRegion(comp, *i, widget->m_visible_region);
49 }
50
51 void eWidgetDesktop::recalcClipRegions()
52 {
53         if (m_comp_mode == cmImmediate)
54                 m_screen.m_background_region = gRegion(eRect(ePoint(0, 0), m_screen.m_screen_size));
55         
56         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
57         {
58                 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
59                 
60                 if (m_comp_mode != cmImmediate)
61                 {
62                         if (!comp)
63                         {
64                                 createBufferForWidget(*i);
65                                 comp = i->m_comp_buffer;
66                         }
67                         
68                         comp->m_background_region = gRegion(eRect(ePoint(0, 0), comp->m_screen_size));
69                 }
70                 
71                 calcWidgetClipRegion(comp, *i, comp->m_background_region);
72         }
73 }
74
75 void eWidgetDesktop::invalidate(const gRegion &region)
76 {
77         if (m_timer && !m_require_redraw)
78                 m_timer->start(0, 1); // start singleshot redraw timer
79         
80         m_require_redraw = 1;
81         
82         if (m_comp_mode == cmImmediate)
83                 m_screen.m_dirty_region |= region;
84         else
85                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
86                 {
87                         eWidgetDesktopCompBuffer *comp = i->m_comp_buffer;
88                         
89                         gRegion mregion = region;
90                         mregion.moveBy(-comp->m_position);
91                         comp->m_dirty_region |= mregion;
92                 }
93 }
94
95 void eWidgetDesktop::setBackgroundColor(eWidgetDesktopCompBuffer *comp, gRGB col)
96 {
97         comp->m_background_color = col;
98         
99                 /* if there's something visible from the background, redraw it with the new color. */
100         if (comp->m_dc && comp->m_background_region.valid() && !comp->m_background_region.empty())
101         {
102                         /* todo: split out "setBackgroundColor / clear"... maybe? */
103                 gPainter painter(comp->m_dc);
104                 painter.resetClip(comp->m_background_region);
105                 painter.setBackgroundColor(comp->m_background_color);
106                 painter.clear();
107         }
108 }
109
110 void eWidgetDesktop::setBackgroundColor(gRGB col)
111 {
112         setBackgroundColor(&m_screen, col);
113
114         if (m_comp_mode == cmBuffered)
115                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
116                         setBackgroundColor(i->m_comp_buffer, col);
117 }
118
119 void eWidgetDesktop::setPalette(gPixmap &pm)
120 {
121         if (m_comp_mode == cmImmediate)
122         {
123                 ASSERT(m_screen.m_dc);
124                 gPainter painter(m_screen.m_dc);
125                 painter.setPalette(&pm);
126         }
127         
128         if (m_comp_mode == cmBuffered)
129         {
130                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
131                 {
132                         ASSERT(i->m_comp_buffer->m_dc);
133                         gPainter painter(i->m_comp_buffer->m_dc);
134                         painter.setPalette(&pm);
135                 }
136         }
137 }
138
139 void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
140 {
141         comp->m_dirty_region &= comp->m_background_region;
142         
143         gPainter painter(comp->m_dc);
144         
145         painter.resetClip(comp->m_dirty_region);
146         painter.setBackgroundColor(comp->m_background_color);
147         painter.clear();
148         painter.flush();
149         
150         comp->m_dirty_region = gRegion();
151 }
152
153 void eWidgetDesktop::paint()
154 {
155         eDebug("paint");
156         m_require_redraw = 0;
157         
158                 /* walk all root windows. */
159         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
160         {
161                 eWidgetDesktopCompBuffer *comp = (m_comp_mode == cmImmediate) ? &m_screen : i->m_comp_buffer;
162                 
163                 {
164                         gPainter painter(comp->m_dc);
165                         i->doPaint(painter, comp->m_dirty_region);
166                 }
167
168                 if (m_comp_mode != cmImmediate)
169                         paintBackground(comp);
170         }
171         
172         if (m_comp_mode == cmImmediate)
173                 paintBackground(&m_screen);
174         
175         if (m_comp_mode == cmBuffered)
176         {
177                 eDebug("redraw composition");
178                 redrawComposition();            
179         }
180 }
181
182 void eWidgetDesktop::setDC(gDC *dc)
183 {
184         m_screen.m_dc = dc;
185 }
186
187 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
188 {
189         if (m_mainloop)
190         {
191                 delete m_timer;
192                 m_timer = 0;
193                 m_mainloop = 0;
194         }
195         m_mainloop = &ml;
196         m_timer = new eTimer(m_mainloop);
197         CONNECT(m_timer->timeout, eWidgetDesktop::paint);
198         
199         if (m_require_redraw)
200                 m_timer->start(0, 1);
201 }
202
203 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
204 {
205         if (m_comp_mode != cmImmediate)
206                 return;
207         
208         eDebug("widgetDesktop: make compatible pixmap of %p\n", &pm);
209         if (!m_screen.m_dc)
210         {
211                 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
212                 return;
213         }
214
215         ePtr<gDC> pixmap_dc = new gDC(&pm);
216         gPainter pixmap_painter(pixmap_dc);
217         
218         ePtr<gPixmap> target_pixmap;
219         m_screen.m_dc->getPixmap(target_pixmap);
220         
221         assert(target_pixmap);
222         
223         pixmap_painter.mergePalette(target_pixmap);
224 }
225
226 void eWidgetDesktop::setCompositionMode(int mode)
227 {
228         m_comp_mode = mode;
229         
230         if (mode == cmBuffered)
231                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
232                         createBufferForWidget(*i);
233         else
234                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
235                         removeBufferForWidget(*i);
236 }
237
238 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
239 {
240         m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
241         m_screen.m_screen_size = size;
242         m_require_redraw = 0;
243
244         setCompositionMode(cmImmediate);
245 }
246
247 eWidgetDesktop::~eWidgetDesktop()
248 {
249                 /* destroy all buffers */
250         setCompositionMode(-1);
251 }
252
253 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
254 {
255         removeBufferForWidget(widget);
256         
257         eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
258         
259         eRect bbox = widget->m_clip_region.extends;
260         comp->m_position = bbox.topLeft();
261         comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
262         comp->m_screen_size = bbox.size();
263                 /* TODO: configurable bit depth. */
264         comp->m_dc = new gDC(new gPixmap(comp->m_screen_size, 32));
265 }
266
267 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
268 {
269         if (widget->m_comp_buffer)
270         {
271                 delete widget->m_comp_buffer;
272                 widget->m_comp_buffer = 0;
273         }
274 }
275
276 void eWidgetDesktop::redrawComposition()
277 {
278         gPainter p(m_screen.m_dc);
279
280         for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
281         {
282                 ePtr<gPixmap> pm;
283                 ASSERT(i->m_comp_buffer);
284                 i->m_comp_buffer->m_dc->getPixmap(pm);
285                 p.blit(pm, i->m_comp_buffer->m_position, eRect(), gPixmap::blitAlphaTest);
286         }
287 }