1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | *********************************************************************/ |
20 | |
21 | #ifndef KWIN_SCENE_H |
22 | #define KWIN_SCENE_H |
23 | |
24 | #include "toplevel.h" |
25 | #include "utils.h" |
26 | #include "kwineffects.h" |
27 | |
28 | #include <QElapsedTimer> |
29 | |
30 | class QGraphicsView; |
31 | |
32 | namespace KWin |
33 | { |
34 | |
35 | class AbstractThumbnailItem; |
36 | class Workspace; |
37 | class Deleted; |
38 | class EffectFrameImpl; |
39 | class EffectWindowImpl; |
40 | class OverlayWindow; |
41 | class Shadow; |
42 | class WindowPixmap; |
43 | |
44 | // The base class for compositing backends. |
45 | class Scene : public QObject |
46 | { |
47 | Q_OBJECT |
48 | public: |
49 | explicit Scene(Workspace* ws); |
50 | virtual ~Scene() = 0; |
51 | class EffectFrame; |
52 | class Window; |
53 | |
54 | // Returns true if the ctor failed to properly initialize. |
55 | virtual bool initFailed() const = 0; |
56 | virtual CompositingType compositingType() const = 0; |
57 | |
58 | virtual bool hasPendingFlush() const { return false; } |
59 | |
60 | // Repaints the given screen areas, windows provides the stacking order. |
61 | // The entry point for the main part of the painting pass. |
62 | // returns the time since the last vblank signal - if there's one |
63 | // ie. "what of this frame is lost to painting" |
64 | virtual qint64 paint(QRegion damage, ToplevelList windows) = 0; |
65 | |
66 | // Notification function - KWin core informs about changes. |
67 | // Used to mainly discard cached data. |
68 | |
69 | // a new window has been created |
70 | virtual void windowAdded(Toplevel*) = 0; |
71 | /** |
72 | * Method invoked when the screen geometry is changed. |
73 | * Reimplementing classes should also invoke the parent method |
74 | * as it takes care of resizing the overlay window. |
75 | * @param size The new screen geometry size |
76 | **/ |
77 | virtual void screenGeometryChanged(const QSize &size); |
78 | // Flags controlling how painting is done. |
79 | enum { |
80 | // Window (or at least part of it) will be painted opaque. |
81 | PAINT_WINDOW_OPAQUE = 1 << 0, |
82 | // Window (or at least part of it) will be painted translucent. |
83 | PAINT_WINDOW_TRANSLUCENT = 1 << 1, |
84 | // Window will be painted with transformed geometry. |
85 | PAINT_WINDOW_TRANSFORMED = 1 << 2, |
86 | // Paint only a region of the screen (can be optimized, cannot |
87 | // be used together with TRANSFORMED flags). |
88 | PAINT_SCREEN_REGION = 1 << 3, |
89 | // Whole screen will be painted with transformed geometry. |
90 | PAINT_SCREEN_TRANSFORMED = 1 << 4, |
91 | // At least one window will be painted with transformed geometry. |
92 | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS = 1 << 5, |
93 | // Clear whole background as the very first step, without optimizing it |
94 | PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6, |
95 | // PAINT_DECORATION_ONLY = 1 << 7 has been removed |
96 | // Window will be painted with a lanczos filter. |
97 | PAINT_WINDOW_LANCZOS = 1 << 8 |
98 | // PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS = 1 << 9 has been removed |
99 | }; |
100 | // types of filtering available |
101 | enum ImageFilterType { ImageFilterFast, ImageFilterGood }; |
102 | // there's nothing to paint (adjust time_diff later) |
103 | virtual void idle(); |
104 | virtual bool blocksForRetrace() const; |
105 | virtual bool syncsToVBlank() const; |
106 | virtual OverlayWindow* overlayWindow() = 0; |
107 | public Q_SLOTS: |
108 | // a window has been destroyed |
109 | virtual void windowDeleted(KWin::Deleted*) = 0; |
110 | // opacity of a window changed |
111 | virtual void windowOpacityChanged(KWin::Toplevel* c) = 0; |
112 | // shape/size of a window changed |
113 | virtual void windowGeometryShapeChanged(KWin::Toplevel* c) = 0; |
114 | // a window has been closed |
115 | virtual void windowClosed(KWin::Toplevel* c, KWin::Deleted* deleted) = 0; |
116 | protected: |
117 | // shared implementation, starts painting the screen |
118 | void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint, |
119 | QRegion *updateRegion, QRegion *validRegion); |
120 | friend class EffectsHandlerImpl; |
121 | // called after all effects had their paintScreen() called |
122 | void finalPaintScreen(int mask, QRegion region, ScreenPaintData& data); |
123 | // shared implementation of painting the screen in the generic |
124 | // (unoptimized) way |
125 | virtual void paintGenericScreen(int mask, ScreenPaintData data); |
126 | // shared implementation of painting the screen in an optimized way |
127 | virtual void paintSimpleScreen(int mask, QRegion region); |
128 | // paint the background (not the desktop background - the whole background) |
129 | virtual void paintBackground(QRegion region) = 0; |
130 | // called after all effects had their paintWindow() called |
131 | void finalPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); |
132 | // shared implementation, starts painting the window |
133 | virtual void paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads); |
134 | // called after all effects had their drawWindow() called |
135 | virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); |
136 | // let the scene decide whether it's better to paint more of the screen, eg. in order to allow a buffer swap |
137 | // the default is NOOP |
138 | virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); |
139 | virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); |
140 | // compute time since the last repaint |
141 | void updateTimeDiff(); |
142 | // saved data for 2nd pass of optimized screen painting |
143 | struct Phase2Data { |
144 | Phase2Data(Window* w, QRegion r, QRegion c, int m, const WindowQuadList& q) |
145 | : window(w), region(r), clip(c), mask(m), quads(q) {} |
146 | Phase2Data() { |
147 | window = 0; |
148 | mask = 0; |
149 | } |
150 | Window* window; |
151 | QRegion region; |
152 | QRegion clip; |
153 | int mask; |
154 | WindowQuadList quads; |
155 | }; |
156 | // windows in their stacking order |
157 | QVector< Window* > stacking_order; |
158 | // The region which actually has been painted by paintScreen() and should be |
159 | // copied from the buffer to the screen. I.e. the region returned from Scene::paintScreen(). |
160 | // Since prePaintWindow() can extend areas to paint, these changes would have to propagate |
161 | // up all the way from paintSimpleScreen() up to paintScreen(), so save them here rather |
162 | // than propagate them up in arguments. |
163 | QRegion painted_region; |
164 | // Additional damage that needs to be repaired to bring a reused back buffer up to date |
165 | QRegion repaint_region; |
166 | // The dirty region before it was unioned with repaint_region |
167 | QRegion damaged_region; |
168 | // time since last repaint |
169 | int time_diff; |
170 | QElapsedTimer last_time; |
171 | Workspace* wspace; |
172 | private: |
173 | void paintWindowThumbnails(Scene::Window *w, QRegion region, qreal opacity, qreal brightness, qreal saturation); |
174 | void paintDesktopThumbnails(Scene::Window *w); |
175 | /** |
176 | * Helper function to find the GraphicsView the ThumbnailItem @p item is rendered in which |
177 | * matches our Window @p w. |
178 | * If not found @c NULL is returned. |
179 | **/ |
180 | QGraphicsView *findViewForThumbnailItem(AbstractThumbnailItem *item, Scene::Window *w); |
181 | QPoint findOffsetInWindow(QWidget *view, xcb_window_t idOfTopmostWindow); |
182 | }; |
183 | |
184 | // The base class for windows representations in composite backends |
185 | class Scene::Window |
186 | { |
187 | public: |
188 | Window(Toplevel* c); |
189 | virtual ~Window(); |
190 | // perform the actual painting of the window |
191 | virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0; |
192 | // do any cleanup needed when the window's composite pixmap is discarded |
193 | void pixmapDiscarded(); |
194 | int x() const; |
195 | int y() const; |
196 | int width() const; |
197 | int height() const; |
198 | QRect geometry() const; |
199 | QPoint pos() const; |
200 | QSize size() const; |
201 | QRect rect() const; |
202 | // access to the internal window class |
203 | // TODO eventually get rid of this |
204 | Toplevel* window(); |
205 | // should the window be painted |
206 | bool isPaintingEnabled() const; |
207 | void resetPaintingEnabled(); |
208 | // Flags explaining why painting should be disabled |
209 | enum { |
210 | // Window will not be painted |
211 | PAINT_DISABLED = 1 << 0, |
212 | // Window will not be painted because it is deleted |
213 | PAINT_DISABLED_BY_DELETE = 1 << 1, |
214 | // Window will not be painted because of which desktop it's on |
215 | PAINT_DISABLED_BY_DESKTOP = 1 << 2, |
216 | // Window will not be painted because it is minimized |
217 | PAINT_DISABLED_BY_MINIMIZE = 1 << 3, |
218 | // Window will not be painted because it is not the active window in a client group |
219 | PAINT_DISABLED_BY_TAB_GROUP = 1 << 4, |
220 | // Window will not be painted because it's not on the current activity |
221 | PAINT_DISABLED_BY_ACTIVITY = 1 << 5 |
222 | }; |
223 | void enablePainting(int reason); |
224 | void disablePainting(int reason); |
225 | // is the window visible at all |
226 | bool isVisible() const; |
227 | // is the window fully opaque |
228 | bool isOpaque() const; |
229 | // shape of the window |
230 | const QRegion &shape() const; |
231 | QRegion clientShape() const; |
232 | void discardShape(); |
233 | void updateToplevel(Toplevel* c); |
234 | // creates initial quad list for the window |
235 | virtual WindowQuadList buildQuads(bool force = false) const; |
236 | void suspendUnredirect(bool suspend); |
237 | void updateShadow(Shadow* shadow); |
238 | const Shadow* shadow() const; |
239 | Shadow* shadow(); |
240 | void referencePreviousPixmap(); |
241 | void unreferencePreviousPixmap(); |
242 | protected: |
243 | WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg) const; |
244 | WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion ®ion) const; |
245 | /** |
246 | * @brief Returns the WindowPixmap for this Window. |
247 | * |
248 | * If the WindowPixmap does not yet exist, this method will invoke @link createWindowPixmap. |
249 | * If the WindowPixmap is not valid it tries to create it, in case this succeeds the WindowPixmap is |
250 | * returned. In case it fails, the previous (and still valid) WindowPixmap is returned. |
251 | * |
252 | * Note: this method can return @c NULL as there might neither be a valid previous nor current WindowPixmap |
253 | * around. |
254 | * |
255 | * The WindowPixmap gets casted to the type passed in as a template parameter. That way this class does not |
256 | * need to know the actual WindowPixmap subclass used by the concrete Scene implementations. |
257 | * |
258 | * @return The WindowPixmap casted to T* or @c NULL if there is no valid window pixmap. |
259 | */ |
260 | template<typename T> T *windowPixmap(); |
261 | template<typename T> T *previousWindowPixmap(); |
262 | /** |
263 | * @brief Factory method to create a WindowPixmap. |
264 | * |
265 | * The inheriting classes need to implement this method to create a new instance of their WindowPixmap subclass. |
266 | * Note: do not use @link WindowPixmap::create on the created instance. The Scene will take care of that. |
267 | */ |
268 | virtual WindowPixmap *createWindowPixmap() = 0; |
269 | Toplevel* toplevel; |
270 | ImageFilterType filter; |
271 | Shadow *m_shadow; |
272 | private: |
273 | QScopedPointer<WindowPixmap> m_currentPixmap; |
274 | QScopedPointer<WindowPixmap> m_previousPixmap; |
275 | int m_referencePixmapCounter; |
276 | int disable_painting; |
277 | mutable QRegion shape_region; |
278 | mutable bool shape_valid; |
279 | mutable WindowQuadList* cached_quad_list; |
280 | Q_DISABLE_COPY(Window) |
281 | }; |
282 | |
283 | /** |
284 | * @brief Wrapper for a pixmap of the @link Scene::Window. |
285 | * |
286 | * This class encapsulates the functionality to get the pixmap for a window. When initialized the pixmap is not yet |
287 | * mapped to the window and @link isValid will return @c false. The pixmap mapping to the window can be established |
288 | * through @link create. If it succeeds @link isValid will return @c true, otherwise it will keep in the non valid |
289 | * state and it can be tried to create the pixmap mapping again (e.g. in the next frame). |
290 | * |
291 | * This class is not intended to be updated when the pixmap is no longer valid due to e.g. resizing the window. |
292 | * Instead a new instance of this class should be instantiated. The idea behind this is that a valid pixmap does not |
293 | * get destroyed, but can continue to be used. To indicate that a newer pixmap should in generally be around, one can |
294 | * use @link markAsDiscarded. |
295 | * |
296 | * This class is intended to be inherited for the needs of the compositor backends which need further mapping from |
297 | * the native pixmap to the respective rendering format. |
298 | */ |
299 | class WindowPixmap |
300 | { |
301 | public: |
302 | virtual ~WindowPixmap(); |
303 | /** |
304 | * @brief Tries to create the mapping between the Window and the pixmap. |
305 | * |
306 | * In case this method succeeds in creating the pixmap for the window, @link isValid will return @c true otherwise |
307 | * @c false. |
308 | * |
309 | * Inheriting classes should re-implement this method in case they need to add further functionality for mapping the |
310 | * native pixmap to the rendering format. |
311 | */ |
312 | virtual void create(); |
313 | /** |
314 | * @return @c true if the pixmap has been created and is valid, @c false otherwise |
315 | */ |
316 | bool isValid() const; |
317 | /** |
318 | * @return The native X11 pixmap handle |
319 | */ |
320 | xcb_pixmap_t pixmap() const; |
321 | /** |
322 | * @brief Whether this WindowPixmap is considered as discarded. This means the window has changed in a way that a new |
323 | * WindowPixmap should have been created already. |
324 | * |
325 | * @return @c true if this WindowPixmap is considered as discarded, @c false otherwise. |
326 | * @see markAsDiscarded |
327 | */ |
328 | bool isDiscarded() const; |
329 | /** |
330 | * @brief Marks this WindowPixmap as discarded. From now on @link isDiscarded will return @c true. This method should |
331 | * only be used by the Window when it changes in a way that a new pixmap is required. |
332 | * |
333 | * @see isDiscarded |
334 | */ |
335 | void markAsDiscarded(); |
336 | /** |
337 | * The size of the pixmap. |
338 | */ |
339 | const QSize &size() const; |
340 | /** |
341 | * The geometry of the Client's content inside the pixmap. In case of a decorated Client the |
342 | * pixmap also contains the decoration which is not rendered into this pixmap, though. This |
343 | * contentsRect tells where inside the complete pixmap the real content is. |
344 | */ |
345 | const QRect &contentsRect() const; |
346 | |
347 | protected: |
348 | explicit WindowPixmap(Scene::Window *window); |
349 | /** |
350 | * @brief Returns the Toplevel this WindowPixmap belongs to. |
351 | * Note: the Toplevel can change over the lifetime of the WindowPixmap in case the Toplevel is copied to Deleted. |
352 | */ |
353 | Toplevel *toplevel(); |
354 | /** |
355 | * @return The Window this WindowPixmap belongs to |
356 | */ |
357 | Scene::Window *window(); |
358 | private: |
359 | Scene::Window *m_window; |
360 | xcb_pixmap_t m_pixmap; |
361 | QSize m_pixmapSize; |
362 | bool m_discarded; |
363 | QRect m_contentsRect; |
364 | }; |
365 | |
366 | class Scene::EffectFrame |
367 | { |
368 | public: |
369 | EffectFrame(EffectFrameImpl* frame); |
370 | virtual ~EffectFrame(); |
371 | virtual void render(QRegion region, double opacity, double frameOpacity) = 0; |
372 | virtual void free() = 0; |
373 | virtual void freeIconFrame() = 0; |
374 | virtual void freeTextFrame() = 0; |
375 | virtual void freeSelection() = 0; |
376 | virtual void crossFadeIcon() = 0; |
377 | virtual void crossFadeText() = 0; |
378 | |
379 | protected: |
380 | EffectFrameImpl* m_effectFrame; |
381 | }; |
382 | |
383 | inline |
384 | int Scene::Window::x() const |
385 | { |
386 | return toplevel->x(); |
387 | } |
388 | |
389 | inline |
390 | int Scene::Window::y() const |
391 | { |
392 | return toplevel->y(); |
393 | } |
394 | |
395 | inline |
396 | int Scene::Window::width() const |
397 | { |
398 | return toplevel->width(); |
399 | } |
400 | |
401 | inline |
402 | int Scene::Window::height() const |
403 | { |
404 | return toplevel->height(); |
405 | } |
406 | |
407 | inline |
408 | QRect Scene::Window::geometry() const |
409 | { |
410 | return toplevel->geometry(); |
411 | } |
412 | |
413 | inline |
414 | QSize Scene::Window::size() const |
415 | { |
416 | return toplevel->size(); |
417 | } |
418 | |
419 | inline |
420 | QPoint Scene::Window::pos() const |
421 | { |
422 | return toplevel->pos(); |
423 | } |
424 | |
425 | inline |
426 | QRect Scene::Window::rect() const |
427 | { |
428 | return toplevel->rect(); |
429 | } |
430 | |
431 | inline |
432 | Toplevel* Scene::Window::window() |
433 | { |
434 | return toplevel; |
435 | } |
436 | |
437 | inline |
438 | void Scene::Window::updateToplevel(Toplevel* c) |
439 | { |
440 | toplevel = c; |
441 | } |
442 | |
443 | inline |
444 | void Scene::Window::suspendUnredirect(bool suspend) |
445 | { |
446 | toplevel->suspendUnredirect(suspend); |
447 | } |
448 | |
449 | inline |
450 | void Scene::Window::updateShadow(Shadow* shadow) |
451 | { |
452 | m_shadow = shadow; |
453 | } |
454 | |
455 | inline |
456 | const Shadow* Scene::Window::shadow() const |
457 | { |
458 | return m_shadow; |
459 | } |
460 | |
461 | inline |
462 | Shadow* Scene::Window::shadow() |
463 | { |
464 | return m_shadow; |
465 | } |
466 | |
467 | inline |
468 | bool WindowPixmap::isValid() const |
469 | { |
470 | return m_pixmap != XCB_PIXMAP_NONE; |
471 | } |
472 | |
473 | template <typename T> |
474 | inline |
475 | T* Scene::Window::windowPixmap() |
476 | { |
477 | if (m_currentPixmap.isNull()) { |
478 | m_currentPixmap.reset(createWindowPixmap()); |
479 | } |
480 | if (m_currentPixmap->isValid()) { |
481 | return static_cast<T*>(m_currentPixmap.data()); |
482 | } |
483 | m_currentPixmap->create(); |
484 | if (m_currentPixmap->isValid()) { |
485 | return static_cast<T*>(m_currentPixmap.data()); |
486 | } else { |
487 | return static_cast<T*>(m_previousPixmap.data()); |
488 | } |
489 | } |
490 | |
491 | template <typename T> |
492 | inline |
493 | T* Scene::Window::previousWindowPixmap() |
494 | { |
495 | return static_cast<T*>(m_previousPixmap.data()); |
496 | } |
497 | |
498 | inline |
499 | Toplevel* WindowPixmap::toplevel() |
500 | { |
501 | return m_window->window(); |
502 | } |
503 | |
504 | inline |
505 | xcb_pixmap_t WindowPixmap::pixmap() const |
506 | { |
507 | return m_pixmap; |
508 | } |
509 | |
510 | inline |
511 | bool WindowPixmap::isDiscarded() const |
512 | { |
513 | return m_discarded; |
514 | } |
515 | |
516 | inline |
517 | void WindowPixmap::markAsDiscarded() |
518 | { |
519 | m_discarded = true; |
520 | m_window->referencePreviousPixmap(); |
521 | } |
522 | |
523 | inline |
524 | const QRect &WindowPixmap::contentsRect() const |
525 | { |
526 | return m_contentsRect; |
527 | } |
528 | |
529 | inline |
530 | const QSize &WindowPixmap::size() const |
531 | { |
532 | return m_pixmapSize; |
533 | } |
534 | |
535 | } // namespace |
536 | |
537 | #endif |
538 | |