~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/effects/highlightwindow/highlightwindow.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
 
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
#include "highlightwindow.h"
 
22
 
 
23
#include <kdebug.h>
 
24
 
 
25
namespace KWin
 
26
{
 
27
 
 
28
KWIN_EFFECT(highlightwindow, HighlightWindowEffect)
 
29
 
 
30
HighlightWindowEffect::HighlightWindowEffect()
 
31
    : m_finishing(false)
 
32
    , m_fadeDuration(double(animationTime(150)))
 
33
    , m_monitorWindow(NULL)
 
34
{
 
35
    m_atom = XInternAtom(display(), "_KDE_WINDOW_HIGHLIGHT", False);
 
36
    effects->registerPropertyType(m_atom, true);
 
37
 
 
38
    // Announce support by creating a dummy version on the root window
 
39
    unsigned char dummy = 0;
 
40
    XChangeProperty(display(), rootWindow(), m_atom, m_atom, 8, PropModeReplace, &dummy, 1);
 
41
    connect(effects, SIGNAL(windowAdded(EffectWindow*)), this, SLOT(slotWindowAdded(EffectWindow*)));
 
42
    connect(effects, SIGNAL(windowClosed(EffectWindow*)), this, SLOT(slotWindowClosed(EffectWindow*)));
 
43
    connect(effects, SIGNAL(windowDeleted(EffectWindow*)), this, SLOT(slotWindowDeleted(EffectWindow*)));
 
44
    connect(effects, SIGNAL(propertyNotify(EffectWindow*,long)), this, SLOT(slotPropertyNotify(EffectWindow*,long)));
 
45
}
 
46
 
 
47
HighlightWindowEffect::~HighlightWindowEffect()
 
48
{
 
49
    XDeleteProperty(display(), rootWindow(), m_atom);
 
50
    effects->registerPropertyType(m_atom, false);
 
51
}
 
52
 
 
53
static bool isInitiallyHidden(EffectWindow* w)
 
54
{
 
55
    // Is the window initially hidden until it is highlighted?
 
56
    return !w->visibleInClientGroup() || !w->isOnCurrentDesktop();
 
57
}
 
58
 
 
59
void HighlightWindowEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
 
60
{
 
61
    // Calculate window opacities
 
62
    if (!m_highlightedWindows.isEmpty()) {
 
63
        // Initial fade out and changing highlight animation
 
64
        double oldOpacity = m_windowOpacity[w];
 
65
        if (m_highlightedWindows.contains(w))
 
66
            m_windowOpacity[w] = qMin(1.0, m_windowOpacity[w] + time / m_fadeDuration);
 
67
        else if (w->isNormalWindow() || w->isDialog())   // Only fade out windows
 
68
            m_windowOpacity[w] = qMax(isInitiallyHidden(w) ? 0.0 : 0.15,
 
69
                                      m_windowOpacity[w] - time / m_fadeDuration);
 
70
 
 
71
        if (m_windowOpacity[w] != 1.0)
 
72
            data.setTranslucent();
 
73
        if (oldOpacity != m_windowOpacity[w])
 
74
            w->addRepaintFull();
 
75
    } else if (m_finishing && m_windowOpacity.contains(w)) {
 
76
        // Final fading back in animation
 
77
        double oldOpacity = m_windowOpacity[w];
 
78
        if (isInitiallyHidden(w))
 
79
            m_windowOpacity[w] = qMax(0.0, m_windowOpacity[w] - time / m_fadeDuration);
 
80
        else
 
81
            m_windowOpacity[w] = qMin(1.0, m_windowOpacity[w] + time / m_fadeDuration);
 
82
 
 
83
        if (m_windowOpacity[w] != 1.0)
 
84
            data.setTranslucent();
 
85
        if (oldOpacity != m_windowOpacity[w])
 
86
            w->addRepaintFull();
 
87
 
 
88
        if (m_windowOpacity[w] == 1.0 || m_windowOpacity[w] == 0.0)
 
89
            m_windowOpacity.remove(w);   // We default to 1.0
 
90
    }
 
91
 
 
92
    // Show tabbed windows and windows on other desktops if highlighted
 
93
    if (m_windowOpacity.contains(w) && m_windowOpacity[w] != 0.0) {
 
94
        if (!w->visibleInClientGroup())
 
95
            w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP);
 
96
        if (!w->isOnCurrentDesktop())
 
97
            w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
 
98
    }
 
99
 
 
100
    effects->prePaintWindow(w, data, time);
 
101
}
 
102
 
 
103
void HighlightWindowEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
 
104
{
 
105
    if (m_windowOpacity.contains(w))
 
106
        data.opacity *= m_windowOpacity[w];
 
107
    effects->paintWindow(w, mask, region, data);
 
108
}
 
109
 
 
110
void HighlightWindowEffect::slotWindowAdded(EffectWindow* w)
 
111
{
 
112
    if (!m_highlightedWindows.isEmpty()) {
 
113
        // The effect is activated thus we need to add it to the opacity hash
 
114
        if (w->isNormalWindow() || w->isDialog())   // Only fade out windows
 
115
            m_windowOpacity[w] = isInitiallyHidden(w) ? 0.0 : 0.15;
 
116
        else
 
117
            m_windowOpacity[w] = 1.0;
 
118
    }
 
119
    slotPropertyNotify(w, m_atom);   // Check initial value
 
120
}
 
121
 
 
122
void HighlightWindowEffect::slotWindowClosed(EffectWindow* w)
 
123
{
 
124
    if (m_monitorWindow == w)   // The monitoring window was destroyed
 
125
        finishHighlighting();
 
126
}
 
127
 
 
128
void HighlightWindowEffect::slotWindowDeleted(EffectWindow* w)
 
129
{
 
130
    m_windowOpacity.remove(w);
 
131
}
 
132
 
 
133
void HighlightWindowEffect::slotPropertyNotify(EffectWindow* w, long a)
 
134
{
 
135
    if (a != m_atom)
 
136
        return; // Not our atom
 
137
 
 
138
    // if the window is null, the property was set on the root window - see events.cpp
 
139
    QByteArray byteData = w ? w->readProperty(m_atom, m_atom, 32) :
 
140
                          effects->readRootProperty(m_atom, m_atom, 32);
 
141
    if (byteData.length() < 1) {
 
142
        // Property was removed, clearing highlight
 
143
        finishHighlighting();
 
144
        return;
 
145
    }
 
146
    long* data = reinterpret_cast<long*>(byteData.data());
 
147
 
 
148
    if (!data[0]) {
 
149
        // Purposely clearing highlight by issuing a NULL target
 
150
        finishHighlighting();
 
151
        return;
 
152
    }
 
153
    m_monitorWindow = w;
 
154
    bool found = false;
 
155
    int length = byteData.length() / sizeof(data[0]);
 
156
    //foreach ( EffectWindow* e, m_highlightedWindows )
 
157
    //    effects->setElevatedWindow( e, false );
 
158
    m_highlightedWindows.clear();
 
159
    for (int i = 0; i < length; i++) {
 
160
        EffectWindow* foundWin = effects->findWindow(data[i]);
 
161
        if (!foundWin) {
 
162
            kDebug(1212) << "Invalid window targetted for highlight. Requested:" << data[i];
 
163
            continue;
 
164
        }
 
165
        if (!foundWin->isMinimized()) {
 
166
            m_highlightedWindows.append(foundWin);
 
167
            // TODO: We cannot just simply elevate the window as this will elevate it over
 
168
            // Plasma tooltips and other such windows as well
 
169
            //effects->setElevatedWindow( foundWin, true );
 
170
        }
 
171
        found = true;
 
172
    }
 
173
    if (!found) {
 
174
        finishHighlighting();
 
175
        return;
 
176
    }
 
177
    prepareHighlighting();
 
178
    if (w)
 
179
        m_windowOpacity[w] = 1.0; // Because it's not in stackingOrder() yet
 
180
 
 
181
    /* TODO: Finish thumbnails of offscreen windows, not sure if it's worth it though
 
182
    if ( !m_highlightedWindow->isOnCurrentDesktop() )
 
183
        { // Window is offscreen, determine thumbnail position
 
184
        QRect screenArea = effects->clientArea( MaximizeArea ); // Workable area of the active screen
 
185
        QRect outerArea = outerArea.adjusted( outerArea.width() / 10, outerArea.height() / 10,
 
186
            -outerArea.width() / 10, -outerArea.height() / 10 ); // Add 10% margin around the edge
 
187
        QRect innerArea = outerArea.adjusted( outerArea.width() / 40, outerArea.height() / 40,
 
188
            -outerArea.width() / 40, -outerArea.height() / 40 ); // Outer edge of the thumbnail border (2.5%)
 
189
        QRect thumbArea = outerArea.adjusted( 20, 20, -20, -20 ); // Outer edge of the thumbnail (20px)
 
190
 
 
191
        // Determine the maximum size that we can make the thumbnail within the innerArea
 
192
        double areaAspect = double( thumbArea.width() ) / double( thumbArea.height() );
 
193
        double windowAspect = aspectRatio( m_highlightedWindow );
 
194
        QRect thumbRect; // Position doesn't matter right now, but it will later
 
195
        if ( windowAspect > areaAspect )
 
196
            // Top/bottom will touch first
 
197
            thumbRect = QRect( 0, 0, widthForHeight( thumbArea.height() ), thumbArea.height() );
 
198
        else // Left/right will touch first
 
199
            thumbRect = QRect( 0, 0, thumbArea.width(), heightForWidth( thumbArea.width() ));
 
200
        if ( thumbRect.width() >= m_highlightedWindow->width() )
 
201
            // Area is larger than the window, just use the window's size
 
202
            thumbRect = m_highlightedWindow->geometry();
 
203
 
 
204
        // Determine position of desktop relative to the current one
 
205
        QPoint direction = effects->desktopGridCoords( m_highlightedWindow->desktop() ) -
 
206
            effects->desktopGridCoords( effects->currentDesktop() );
 
207
 
 
208
        // Draw a line from the center of the current desktop to the center of the target desktop.
 
209
        QPointF desktopLine( 0, 0, direction.x() * screenArea.width(), direction.y() * screenArea.height() );
 
210
        desktopLeft.translate( screenArea.width() / 2, screenArea.height() / 2 ); // Move to the screen center
 
211
 
 
212
        // Take the point where the line crosses the outerArea, this will be the tip of our arrow
 
213
        QPointF arrowTip;
 
214
        QLineF testLine( // Top
 
215
            outerArea.x(), outerArea.y(),
 
216
            outerArea.x() + outerArea.width(), outerArea.y() );
 
217
        if ( desktopLine.intersect( testLine, &arrowTip ) != QLineF::BoundedIntersection )
 
218
            {
 
219
            testLine = QLineF( // Right
 
220
                outerArea.x() + outerArea.width(), outerArea.y(),
 
221
                outerArea.x() + outerArea.width(), outerArea.y() + outerArea.height() );
 
222
            if ( desktopLine.intersect( testLine, &arrowTip ) != QLineF::BoundedIntersection )
 
223
                {
 
224
                testLine = QLineF( // Bottom
 
225
                    outerArea.x() + outerArea.width(), outerArea.y() + outerArea.height(),
 
226
                    outerArea.x(), outerArea.y() + outerArea.height() );
 
227
                if ( desktopLine.intersect( testLine, &arrowTip ) != QLineF::BoundedIntersection )
 
228
                    {
 
229
                    testLine = QLineF( // Left
 
230
                        outerArea.x(), outerArea.y() + outerArea.height(),
 
231
                        outerArea.x(), outerArea.y() );
 
232
                    desktopLine.intersect( testLine, &arrowTip ); // Should never fail
 
233
                    }
 
234
                }
 
235
            }
 
236
        m_arrowTip = arrowTip.toPoint();
 
237
        } */
 
238
}
 
239
 
 
240
void HighlightWindowEffect::prepareHighlighting()
 
241
{
 
242
    // Create window data for every window. Just calling [w] creates it.
 
243
    m_finishing = false;
 
244
    foreach (EffectWindow * w, effects->stackingOrder())
 
245
    if (!m_windowOpacity.contains(w))    // Just in case we are still finishing from last time
 
246
        m_windowOpacity[w] = isInitiallyHidden(w) ? 0.0 : 1.0;
 
247
    if (!m_highlightedWindows.isEmpty())
 
248
        m_highlightedWindows.at(0)->addRepaintFull();
 
249
}
 
250
 
 
251
void HighlightWindowEffect::finishHighlighting()
 
252
{
 
253
    m_finishing = true;
 
254
    m_monitorWindow = NULL;
 
255
    m_highlightedWindows.clear();
 
256
    if (!m_windowOpacity.isEmpty())
 
257
        m_windowOpacity.constBegin().key()->addRepaintFull();
 
258
}
 
259
 
 
260
} // namespace