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