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