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 }