File indexing completed on 2024-05-12 05:46:41

0001 /* This file is part of the KDE libraries
0002    Copyright (C) 2014 Thomas Lübking <thomas.luebking@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License version 2 as published by the Free Software Foundation.
0007 
0008    This library is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0011    Library General Public License for more details.
0012 
0013    You should have received a copy of the GNU Library General Public License
0014    along with this library; see the file COPYING.LIB. If not, write to
0015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0016    Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "kstyleextensions.h"
0020 
0021 #include <QWidget>
0022 
0023 namespace KStyleExtensions
0024 {
0025 
0026 
0027 /*
0028     Custom Style Element runtime extension:
0029     We reserve one StyleHint to let the effective style inform widgets whether it supports certain
0030     string based style elements.
0031     As this could lead to number conflicts (i.e. an app utilizing one of the hints itself for other
0032     purposes) there're various safety mechanisms to rule out such interference.
0033 
0034     1) It's most unlikely that a widget in some 3rd party app will accidentally call a general
0035     QStyle/KStyle styleHint() or draw*() and (unconditionally) expect a valid return, however:
0036         a. The StyleHint is not directly above Qt's custom base, assuming most 3rd party apps would
0037            - in case - make use of such
0038         b. In order to be accepted, the StyleHint query must pass a widget with a perfectly matching
0039            name, containing the typical element prefix ("CE_", etc.) and being supported by the current
0040            style
0041         c. Instead using Qt's fragile qstyleoption_cast on the QStyleOption provided to the StyleHint
0042            query, try to dump out a string and hope for the best, we now manipulate the widgets
0043            objectName().
0044            Plain Qt dependent widgets can do that themselves and if a widget uses KStyle's
0045            convenience access functions, it won't notice this at all
0046 
0047     2) The key problem is that a common KDE widget will run into an apps custom style which will then
0048     falsely respond to the styleHint() call with an invalid value.
0049     To prevent this, supporting styles *must* set a Q_CLASSINFO "X-KDE-CustomElements".
0050 
0051     3) If any of the above traps snaps, the returned id is 0 - the QStyle default, indicating
0052     that this element is not supported by the current style.
0053 
0054     Obviously, this contains the "diminished clean" action to (temporarily) manipulate the
0055     objectName() of a const QWidget* - but this happens completely inside KStyle or the widget, if
0056     it does not make use of KStyles static convenience functions.
0057     My biggest worry here would be, that in a multithreaded environment a thread (usually not being
0058     owner of the widget) does something crucially relying on the widgets name property...
0059     This however would also have to happen during the widget construction or stylechanges, when
0060     the functions in doubt will typically be called.
0061     So this is imho unlikely causing any trouble, ever.
0062 */
0063 
0064 static const QStyle::StyleHint SH_KCustomStyleElement = (QStyle::StyleHint)0xff000001;
0065 static const int X_KdeBase = 0xff000000;
0066 
0067 /*
0068     The functions called by widgets that request custom element support, passed to the effective style.
0069     Collected in a static inline function due to similarity.
0070 */
0071 
0072 static inline int customStyleElement(QStyle::StyleHint type, const QString &element, QWidget *widget)
0073 {
0074     if (!widget || widget->style()->metaObject()->indexOfClassInfo("X-KDE-CustomElements") < 0)
0075         return 0;
0076 
0077     const QString originalName = widget->objectName();
0078     widget->setObjectName(element);
0079     const int id = widget->style()->styleHint(type, nullptr, widget);
0080     widget->setObjectName(originalName);
0081     return id;
0082 }
0083 
0084 QStyle::StyleHint customStyleHint(const QString &element, const QWidget *widget)
0085 {
0086     return (QStyle::StyleHint) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget*>(widget));
0087 }
0088 
0089 QStyle::ControlElement customControlElement(const QString &element, const QWidget *widget)
0090 {
0091     return (QStyle::ControlElement) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget*>(widget));
0092 }
0093 
0094 QStyle::SubElement customSubElement(const QString &element, const QWidget *widget)
0095 {
0096     return (QStyle::SubElement) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget*>(widget));
0097 }
0098 
0099 }