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 // WinIdChange Event, should not happen though
79 widget->installEventFilter(this);
80 installX11Shadows(widget);
81 return true;
82 }
83
84 void
unregisterWidget(QWidget * widget)85 ShadowHelper::unregisterWidget(QWidget *widget)
86 {
87 QtcQWidgetProps props(widget);
88 if (props->shadowRegistered) {
89 uninstallX11Shadows(widget);
90 props->shadowRegistered = false;
91 }
92 }
93
94 bool
eventFilter(QObject * object,QEvent * event)95 ShadowHelper::eventFilter(QObject *object, QEvent *event)
96 {
97 if (event->type() == QEvent::WinIdChange)
98 installX11Shadows(static_cast<QWidget*>(object));
99 return false;
100 }
101
102 bool
acceptWidget(QWidget * widget) const103 ShadowHelper::acceptWidget(QWidget *widget) const
104 {
105 if (widget->property(netWMSkipShadowPropertyName).toBool())
106 return false;
107 if (widget->property(netWMForceShadowPropertyName).toBool())
108 return true;
109
110 // menus
111 if (qobject_cast<QMenu*>(widget))
112 return true;
113
114 // combobox dropdown lists
115 if (widget->inherits("QComboBoxPrivateContainer"))
116 return true;
117
118 // tooltips
119 if ((widget->windowType() == Qt::ToolTip ||
120 widget->inherits("QTipLabel")) && !widget->inherits("Plasma::ToolTip"))
121 return true;
122
123 // detached widgets
124 if (qobject_cast<QToolBar*>(widget) || qobject_cast<QDockWidget*>(widget))
125 return true;
126
127 // reject
128 return false;
129 }
130
131 bool
installX11Shadows(QWidget * widget)132 ShadowHelper::installX11Shadows(QWidget *widget)
133 {
134 // DO NOT condition compile on QTC_ENABLE_X11.
135 // There's no direct linkage on X11 and the following code will just do
136 // nothing if X11 is not enabled (either at compile time or at run time).
137 QTC_RET_IF_FAIL(qtcX11Enabled(), false);
138 if (WId wid = qtcGetWid(widget)) {
139 if (widget->windowType() == Qt::ToolTip &&
140 widget->inherits("QBalloonTip")) {
141 bool atTop = true;
142 int margin = qtcGetBalloonMargin(widget, &atTop);
143 int margins[4] = {0, 0, 0, 0};
144 // KWin's shadows margin order is top, right, bottom, left..
145 margins[atTop ? 0 : 2] = margin;
146 qtcX11ShadowInstall(wid, margins);
147 } else {
148 qtcX11ShadowInstall(wid);
149 }
150 return true;
151 }
152 return false;
153 }
154
155 void
uninstallX11Shadows(QWidget * widget) const156 ShadowHelper::uninstallX11Shadows(QWidget *widget) const
157 {
158 // DO NOT condition compile on QTC_ENABLE_X11.
159 // There's no direct linkage on X11 and the following code will just do
160 // nothing if X11 is not enabled (either at compile time or at run time).
161 QTC_RET_IF_FAIL(qtcX11Enabled());
162 if (WId wid = qtcGetWid(widget)) {
163 qtcX11ShadowUninstall(wid);
164 }
165 }
166 }
167