File: kwinkscreenhelpereffect.cpp

package info (click to toggle)
powerdevil 4%3A6.5.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,680 kB
  • sloc: cpp: 13,284; xml: 1,911; python: 1,204; sh: 19; makefile: 10
file content (161 lines) | stat: -rw-r--r-- 4,733 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 *   SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
 *
 *   SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "kwinkscreenhelpereffect.h"

#include <QCoreApplication>
#include <chrono>
#include <private/qtx11extras_p.h>

using namespace std::chrono_literals;

namespace PowerDevil
{
KWinKScreenHelperEffect::KWinKScreenHelperEffect(QObject *parent)
    : QObject(parent)
{
    m_abortTimer.setSingleShot(true);
    m_abortTimer.setInterval(11s);
    connect(&m_abortTimer, &QTimer::timeout, this, &KWinKScreenHelperEffect::stop);

    qApp->installNativeEventFilter(this);
}

KWinKScreenHelperEffect::~KWinKScreenHelperEffect()
{
    stop();
}

bool KWinKScreenHelperEffect::start()
{
    m_isValid = checkValid();
    if (!m_isValid) {
        // emit fade out right away since the effect is not available
        Q_EMIT fadedOut();
        return false;
    }

    m_running = true;
    setEffectProperty(1);
    m_abortTimer.start();
    return true;
}

void KWinKScreenHelperEffect::stop()
{
    // Maybe somebody got confused, just reset the property then
    if (m_state == NormalState) {
        setEffectProperty(0);
    } else {
        setEffectProperty(3);
    }
    m_running = false;
    m_abortTimer.stop();
}

bool KWinKScreenHelperEffect::checkValid()
{
#if HAVE_XCB
    if (QX11Info::isPlatformX11()) {
        QScopedPointer<xcb_list_properties_reply_t, QScopedPointerPodDeleter> propsReply(
            xcb_list_properties_reply(QX11Info::connection(), xcb_list_properties_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), nullptr));
        QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> atomReply(
            xcb_intern_atom_reply(QX11Info::connection(), xcb_intern_atom_unchecked(QX11Info::connection(), false, 25, "_KDE_KWIN_KSCREEN_SUPPORT"), nullptr));

        if (propsReply.isNull() || atomReply.isNull()) {
            return false;
        }

        auto *atoms = xcb_list_properties_atoms(propsReply.data());
        for (int i = 0; i < propsReply->atoms_len; ++i) {
            if (atoms[i] == atomReply->atom) {
                m_atom = atomReply->atom;
                return true;
            }
        }

        m_atom = 0;
        return false;
    }
#endif
    return false;
}

void KWinKScreenHelperEffect::setEffectProperty(long value)
{
#if HAVE_XCB
    if (m_isValid && QX11Info::isPlatformX11()) {
        xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, QX11Info::appRootWindow(), m_atom, XCB_ATOM_CARDINAL, 32, 1, &value);
    }
#else
    Q_UNUSED(value);
#endif
}

bool KWinKScreenHelperEffect::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
{
    Q_UNUSED(result);

    if (eventType != "xcb_generic_event_t") {
        return false;
    }

#if HAVE_XCB
    if (m_isValid && QX11Info::isPlatformX11()) {
        auto e = static_cast<xcb_generic_event_t *>(message);
        const uint8_t type = e->response_type & ~0x80;
        if (type == XCB_PROPERTY_NOTIFY) {
            auto *event = reinterpret_cast<xcb_property_notify_event_t *>(e);
            if (event->window == QX11Info::appRootWindow()) {
                if (event->atom != m_atom) {
                    return false;
                }

                auto cookie = xcb_get_property(QX11Info::connection(), false, QX11Info::appRootWindow(), m_atom, XCB_ATOM_CARDINAL, 0, 1);
                QScopedPointer<xcb_get_property_reply_t, QScopedPointerPodDeleter> reply(xcb_get_property_reply(QX11Info::connection(), cookie, nullptr));
                if (reply.isNull() || reply.data()->value_len != 1 || reply.data()->format != uint8_t(32)) {
                    return false;
                }

                auto *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.data()));
                if (!data) {
                    return false;
                }

                switch (*data) {
                case 1:
                    m_state = FadingOutState;
                    break;
                case 2:
                    m_state = FadedOutState;
                    if (m_running) {
                        Q_EMIT fadedOut();
                    }
                    break;
                case 3:
                    m_state = FadingInState;
                    m_running = false;
                    m_abortTimer.stop();
                    break;
                default:
                    m_state = NormalState;
                    m_running = false;
                }

                Q_EMIT stateChanged(m_state);
            }
        }
    }
#else
    Q_UNUSED(message);
#endif

    return false;
}

} // namespace PowerDevil

#include "moc_kwinkscreenhelpereffect.cpp"