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