- start working on compositing support
[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
176 void eWidgetDesktop::setDC(gDC *dc)
177 {
178         m_screen.m_dc = dc;
179 }
180
181 void eWidgetDesktop::setRedrawTask(eMainloop &ml)
182 {
183         if (m_mainloop)
184         {
185                 delete m_timer;
186                 m_timer = 0;
187                 m_mainloop = 0;
188         }
189         m_mainloop = &ml;
190         m_timer = new eTimer(m_mainloop);
191         CONNECT(m_timer->timeout, eWidgetDesktop::paint);
192         
193         if (m_require_redraw)
194                 m_timer->start(0, 1);
195 }
196
197 void eWidgetDesktop::makeCompatiblePixmap(gPixmap &pm)
198 {
199         if (m_comp_mode != cmImmediate)
200                 return;
201         
202         eDebug("widgetDesktop: make compatible pixmap of %p\n", &pm);
203         if (!m_screen.m_dc)
204         {
205                 eWarning("eWidgetDesktop: no DC to make pixmap compatible with!");
206                 return;
207         }
208
209         ePtr<gDC> pixmap_dc = new gDC(&pm);
210         gPainter pixmap_painter(pixmap_dc);
211         
212         ePtr<gPixmap> target_pixmap;
213         m_screen.m_dc->getPixmap(target_pixmap);
214         
215         assert(target_pixmap);
216         
217         pixmap_painter.mergePalette(target_pixmap);
218 }
219
220 void eWidgetDesktop::setCompositionMode(int mode)
221 {
222         m_comp_mode = mode;
223         
224         if (mode == cmBuffered)
225                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
226                         createBufferForWidget(*i);
227         else
228                 for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
229                         removeBufferForWidget(*i);
230 }
231
232 eWidgetDesktop::eWidgetDesktop(eSize size): m_mainloop(0), m_timer(0)
233 {
234         m_screen.m_dirty_region = gRegion(eRect(ePoint(0, 0), size));
235         m_screen.m_screen_size = size;
236         m_require_redraw = 0;
237
238         setCompositionMode(cmImmediate);
239 }
240
241 eWidgetDesktop::~eWidgetDesktop()
242 {
243                 /* destroy all buffer */
244         setCompositionMode(-1);
245 }
246
247 void eWidgetDesktop::createBufferForWidget(eWidget *widget)
248 {
249         removeBufferForWidget(widget);
250         
251         eWidgetDesktopCompBuffer *comp = widget->m_comp_buffer = new eWidgetDesktopCompBuffer;
252         
253         eRect bbox = widget->m_clip_region.extends;
254         comp->m_position = bbox.topLeft();
255         comp->m_dirty_region = gRegion(eRect(ePoint(0, 0), bbox.size()));
256         comp->m_screen_size = bbox.size();
257 //      comp->m_dc = new .. ;
258 }
259
260 void eWidgetDesktop::removeBufferForWidget(eWidget *widget)
261 {
262         if (widget->m_comp_buffer)
263         {
264                 delete widget->m_comp_buffer;
265                 widget->m_comp_buffer = 0;
266         }
267 }