Libplasma

contrasteffectwatcher.cpp
1/*
2 SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "contrasteffectwatcher_p.h"
8
9#include <QWaylandClientExtensionTemplate>
10
11#include <KWindowSystem>
12
13#if HAVE_X11
14#include <X11/Xlib.h>
15#endif
16
17#include "qwayland-contrast.h"
18
19namespace Plasma
20{
21
22class ContrastManager : public QWaylandClientExtensionTemplate<ContrastManager>, public QtWayland::org_kde_kwin_contrast_manager
23{
24public:
25 ContrastManager()
26 : QWaylandClientExtensionTemplate<ContrastManager>(2)
27 {
28 }
29 ~ContrastManager()
30 {
31 if (object()) {
32 org_kde_kwin_contrast_manager_destroy(object());
33 }
34 }
35};
36
37ContrastEffectWatcher::ContrastEffectWatcher(QObject *parent)
38 : QObject(parent)
39#if HAVE_X11
40 , m_property(XCB_ATOM_NONE)
41 , m_x11Interface(qGuiApp->nativeInterface<QNativeInterface::QX11Application>())
42#endif
43{
45 m_contrastManager = std::make_unique<ContrastManager>();
46 }
47
48 init();
49}
50
51ContrastEffectWatcher::~ContrastEffectWatcher()
52{
53}
54
55void ContrastEffectWatcher::init()
56{
58 connect(m_contrastManager.get(), &ContrastManager::activeChanged, this, [this]() {
59 m_effectActive = m_contrastManager->isActive();
60 Q_EMIT effectChanged(m_effectActive);
61 });
62 m_effectActive = m_contrastManager->isActive();
63 } else if (KWindowSystem::isPlatformX11()) {
64#if HAVE_X11
65 if (!m_x11Interface) {
66 return;
67 }
69
70 xcb_connection_t *c = m_x11Interface->connection();
71 const QByteArray propertyName("_KDE_NET_WM_BACKGROUND_CONTRAST_REGION");
72 xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, propertyName.length(), propertyName.constData());
73 xcb_get_window_attributes_cookie_t winAttrCookie = xcb_get_window_attributes_unchecked(c, DefaultRootWindow(m_x11Interface->display()));
74
75 QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> atom(xcb_intern_atom_reply(c, atomCookie, nullptr));
76 if (!atom.isNull()) {
77 m_property = atom->atom;
78 }
79
80 m_effectActive = fetchEffectActive();
81
82 QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> attrs(xcb_get_window_attributes_reply(c, winAttrCookie, nullptr));
83 if (!attrs.isNull()) {
84 uint32_t events = attrs->your_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE;
85 xcb_change_window_attributes(c, DefaultRootWindow(m_x11Interface->display()), XCB_CW_EVENT_MASK, &events);
86 }
87#endif
88 }
89}
90
91#if HAVE_X11
92bool ContrastEffectWatcher::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
93{
95 return false;
96 }
97
98 Q_UNUSED(result);
99 // A faster comparison than eventType != "xcb_generic_event_t"
100 // given that eventType can only have the following values:
101 // "xcb_generic_event_t", "windows_generic_MSG" and "mac_generic_NSEvent"
102 // According to https://doc.qt.io/qt-5/qabstractnativeeventfilter.html
103 if (eventType[0] != 'x') {
104 return false;
105 }
106 xcb_generic_event_t *event = reinterpret_cast<xcb_generic_event_t *>(message);
107 uint response_type = event->response_type & ~0x80;
108 if (response_type != XCB_PROPERTY_NOTIFY || m_property == XCB_ATOM_NONE) {
109 return false;
110 }
111
112 xcb_property_notify_event_t *prop_event = reinterpret_cast<xcb_property_notify_event_t *>(event);
113 if (prop_event->atom == m_property) {
114 bool nowEffectActive = fetchEffectActive();
115 if (m_effectActive != nowEffectActive) {
116 m_effectActive = nowEffectActive;
117 Q_EMIT effectChanged(m_effectActive);
118 }
119 }
120
121 return false;
122}
123#endif
124
125bool ContrastEffectWatcher::isEffectActive() const
126{
127 return m_effectActive;
128}
129
130bool ContrastEffectWatcher::fetchEffectActive() const
131{
133 return m_contrastManager->isActive();
134 }
135
136 if (m_property == XCB_ATOM_NONE || !m_x11Interface) {
137 return false;
138 }
139 xcb_connection_t *c = m_x11Interface->connection();
140 xcb_list_properties_cookie_t propsCookie = xcb_list_properties_unchecked(c, DefaultRootWindow(m_x11Interface->display()));
141 QScopedPointer<xcb_list_properties_reply_t, QScopedPointerPodDeleter> props(xcb_list_properties_reply(c, propsCookie, nullptr));
142 if (props.isNull()) {
143 return false;
144 }
145 xcb_atom_t *atoms = xcb_list_properties_atoms(props.data());
146 for (int i = 0; i < props->atoms_len; ++i) {
147 if (atoms[i] == m_property) {
148 return true;
149 }
150 }
151 return false;
152}
153
154} // namespace Plasma
static bool isPlatformX11()
static bool isPlatformWayland()
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
Namespace for everything in libplasma.
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
QCoreApplication * instance()
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:06:24 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.