1 /*****************************************************************************
2 * Copyright 2010 Craig Drummond <craig.p.drummond@gmail.com> *
3 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License as *
7 * published by the Free Software Foundation; either version 2.1 of the *
8 * License, or (at your option) version 3, or any later version accepted *
9 * by the membership of KDE e.V. (or its successor approved by the *
10 * membership of KDE e.V.), which shall act as a proxy defined in *
11 * Section 6 of version 3 of the license. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library. If not, *
20 * see <http://www.gnu.org/licenses/>. *
21 *****************************************************************************/
22
23 //////////////////////////////////////////////////////////////////////////////
24 // shadowhelper.h
25 // handle shadow _pixmaps passed to window manager via X property
26 // -------------------
27 //
28 // Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
29 //
30 // Permission is hereby granted, free of charge, to any person obtaining a copy
31 // of this software and associated documentation files (the "Software"), to
32 // deal in the Software without restriction, including without limitation the
33 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
34 // sell copies of the Software, and to permit persons to whom the Software is
35 // furnished to do so, subject to the following conditions:
36 //
37 // The above copyright notice and this permission notice shall be included in
38 // all copies or substantial portions of the Software.
39 //
40 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
45 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
46 // IN THE SOFTWARE.
47 //////////////////////////////////////////////////////////////////////////////
48
49 #include "shadowhelper.h"
50 #include "utils.h"
51
52 #include <QDockWidget>
53 #include <QMenu>
54 #include <QPainter>
55 #include <QToolBar>
56 #include <QEvent>
57
58 #include <qtcurve-utils/x11shadow.h>
59 #include <qtcurve-utils/qtprops.h>
60
61 namespace QtCurve {
62 const char *const ShadowHelper::netWMForceShadowPropertyName =
63 "_KDE_NET_WM_FORCE_SHADOW";
64 const char *const ShadowHelper::netWMSkipShadowPropertyName =
65 "_KDE_NET_WM_SKIP_SHADOW";
66
67 bool
registerWidget(QWidget * widget,bool force)68 ShadowHelper::registerWidget(QWidget *widget, bool force)
69 {
70 QtcQWidgetProps props(widget);
71 // make sure widget is not already registered
72 if (props->shadowRegistered)
73 return false;
74 // check if widget qualifies
75 if (!(force || acceptWidget(widget)))
76 return false;
77 props->shadowRegistered = true;
78
79 // WinIdChange Event
80 widget->installEventFilter(this);
81 installX11Shadows(widget);
82 return true;
83 }
84
85 void
unregisterWidget(QWidget * widget)86 ShadowHelper::unregisterWidget(QWidget *widget)
87 {
88 QtcQWidgetProps props(widget);
89 if (props->shadowRegistered) {
90 uninstallX11Shadows(widget);
91 props->shadowRegistered = false;
92 }
93 }
94
95 bool
eventFilter(QObject * object,QEvent * event)96 ShadowHelper::eventFilter(QObject *object, QEvent *event)
97 {
98 if (event->type() == QEvent::WinIdChange)
99 installX11Shadows(static_cast<QWidget*>(object));
100 return false;
101 }
102
103 bool
acceptWidget(QWidget * widget) const104 ShadowHelper::acceptWidget(QWidget *widget) const
105 {
106 if (widget->property(netWMSkipShadowPropertyName).toBool())
107 return false;
108 if (widget->property(netWMForceShadowPropertyName).toBool())
109 return true;
110
111 // menus
112 if (qobject_cast<QMenu*>(widget))
113 return true;
114
115 // combobox dropdown lists
116 if (widget->inherits("QComboBoxPrivateContainer"))
117 return true;
118
119 // tooltips
120 if ((widget->windowType() == Qt::ToolTip ||
121 widget->inherits("QTipLabel")) && !widget->inherits("Plasma::ToolTip"))
122 return true;
123
124 // detached widgets
125 if (qobject_cast<QToolBar*>(widget) || qobject_cast<QDockWidget*>(widget))
126 return true;
127
128 // Fix Lancelot main menu shadow. Somehow they sets the override the
129 // shadow of the main menu to nothing instead of the plasma one.
130 // Maybe I should submit a patch for lancelot later instead.
131 if (widget->inherits("LancelotWindow"))
132 return true;
133
134 // reject
135 return false;
136 }
137
138 bool
installX11Shadows(QWidget * widget)139 ShadowHelper::installX11Shadows(QWidget *widget)
140 {
141 // DO NOT condition compile on QTC_ENABLE_X11.
142 // There's no direct linkage on X11 and the following code will just do
143 // nothing if X11 is not enabled (either at compile time or at run time).
144 QTC_RET_IF_FAIL(qtcX11Enabled(), false);
145 if (WId wid = qtcGetWid(widget)) {
146 if (widget->windowType() == Qt::ToolTip &&
147 widget->inherits("QBalloonTip")) {
148 bool atTop = true;
149 int margin = qtcGetBalloonMargin(widget, &atTop);
150 int margins[4] = {0, 0, 0, 0};
151 // KWin's shadows margin order is top, right, bottom, left..
152 margins[atTop ? 0 : 2] = margin;
153 qtcX11ShadowInstall(wid, margins);
154 } else {
155 qtcX11ShadowInstall(wid);
156 }
157 return true;
158 }
159 return false;
160 }
161
162 void
uninstallX11Shadows(QWidget * widget) const163 ShadowHelper::uninstallX11Shadows(QWidget *widget) const
164 {
165 // DO NOT condition compile on QTC_ENABLE_X11.
166 // There's no direct linkage on X11 and the following code will just do
167 // nothing if X11 is not enabled (either at compile time or at run time).
168 QTC_RET_IF_FAIL(qtcX11Enabled());
169 if (WId wid = qtcGetWid(widget)) {
170 qtcX11ShadowUninstall(wid);
171 }
172 }
173 }
174