1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
30class QGraphicsView;
31
32namespace KWin
33{
34
35class AbstractThumbnailItem;
36class Workspace;
37class Deleted;
38class EffectFrameImpl;
39class EffectWindowImpl;
40class OverlayWindow;
41class Shadow;
42class WindowPixmap;
43
44// The base class for compositing backends.
45class Scene : public QObject
46{
47 Q_OBJECT
48public:
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;
107public 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;
116protected:
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 &region, bool opaqueFullscreen);
139 virtual void paintDesktop(int desktop, int mask, const QRegion &region, 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;
172private:
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
185class Scene::Window
186{
187public:
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();
242protected:
243 WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg) const;
244 WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion &region) 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;
272private:
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 */
299class WindowPixmap
300{
301public:
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
347protected:
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();
358private:
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
366class Scene::EffectFrame
367{
368public:
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
379protected:
380 EffectFrameImpl* m_effectFrame;
381};
382
383inline
384int Scene::Window::x() const
385{
386 return toplevel->x();
387}
388
389inline
390int Scene::Window::y() const
391{
392 return toplevel->y();
393}
394
395inline
396int Scene::Window::width() const
397{
398 return toplevel->width();
399}
400
401inline
402int Scene::Window::height() const
403{
404 return toplevel->height();
405}
406
407inline
408QRect Scene::Window::geometry() const
409{
410 return toplevel->geometry();
411}
412
413inline
414QSize Scene::Window::size() const
415{
416 return toplevel->size();
417}
418
419inline
420QPoint Scene::Window::pos() const
421{
422 return toplevel->pos();
423}
424
425inline
426QRect Scene::Window::rect() const
427{
428 return toplevel->rect();
429}
430
431inline
432Toplevel* Scene::Window::window()
433{
434 return toplevel;
435}
436
437inline
438void Scene::Window::updateToplevel(Toplevel* c)
439{
440 toplevel = c;
441}
442
443inline
444void Scene::Window::suspendUnredirect(bool suspend)
445{
446 toplevel->suspendUnredirect(suspend);
447}
448
449inline
450void Scene::Window::updateShadow(Shadow* shadow)
451{
452 m_shadow = shadow;
453}
454
455inline
456const Shadow* Scene::Window::shadow() const
457{
458 return m_shadow;
459}
460
461inline
462Shadow* Scene::Window::shadow()
463{
464 return m_shadow;
465}
466
467inline
468bool WindowPixmap::isValid() const
469{
470 return m_pixmap != XCB_PIXMAP_NONE;
471}
472
473template <typename T>
474inline
475T* 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
491template <typename T>
492inline
493T* Scene::Window::previousWindowPixmap()
494{
495 return static_cast<T*>(m_previousPixmap.data());
496}
497
498inline
499Toplevel* WindowPixmap::toplevel()
500{
501 return m_window->window();
502}
503
504inline
505xcb_pixmap_t WindowPixmap::pixmap() const
506{
507 return m_pixmap;
508}
509
510inline
511bool WindowPixmap::isDiscarded() const
512{
513 return m_discarded;
514}
515
516inline
517void WindowPixmap::markAsDiscarded()
518{
519 m_discarded = true;
520 m_window->referencePreviousPixmap();
521}
522
523inline
524const QRect &WindowPixmap::contentsRect() const
525{
526 return m_contentsRect;
527}
528
529inline
530const QSize &WindowPixmap::size() const
531{
532 return m_pixmapSize;
533}
534
535} // namespace
536
537#endif
538