src/gui/styles/qgtkstyle_p.cpp
changeset 30 5dc02b23752f
parent 19 fcece45ef507
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    58 #include <QtCore/QStringList>
    58 #include <QtCore/QStringList>
    59 #include <QtCore/QTextStream>
    59 #include <QtCore/QTextStream>
    60 #include <QtCore/QHash>
    60 #include <QtCore/QHash>
    61 #include <QtCore/QUrl>
    61 #include <QtCore/QUrl>
    62 #include <QtCore/QLibrary>
    62 #include <QtCore/QLibrary>
       
    63 #include <QtCore/QDebug>
    63 
    64 
    64 #include <private/qapplication_p.h>
    65 #include <private/qapplication_p.h>
    65 #include <private/qiconloader_p.h>
    66 #include <private/qiconloader_p.h>
    66 
    67 
    67 #include <QtGui/QMenu>
    68 #include <QtGui/QMenu>
   231             QApplication::sendEvent(widget, &event);
   232             QApplication::sendEvent(widget, &event);
   232         }
   233         }
   233     }
   234     }
   234 }
   235 }
   235 
   236 
   236 static QString classPath(GtkWidget *widget)
   237 static QHashableLatin1Literal classPath(GtkWidget *widget)
   237 {
   238 {
   238     char* class_path;
   239     char *class_path;
   239     QGtkStylePrivate::gtk_widget_path (widget, NULL, &class_path, NULL);
   240     QGtkStylePrivate::gtk_widget_path (widget, NULL, &class_path, NULL);
   240     QString path = QLS(class_path);
   241 
       
   242     char *copy = class_path;
       
   243     if (strncmp(copy, "GtkWindow.", 10) == 0)
       
   244         copy += 10;
       
   245     if (strncmp(copy, "GtkFixed.", 9) == 0)
       
   246         copy += 9;
       
   247 
       
   248     copy = strdup(copy);
       
   249 
   241     g_free(class_path);
   250     g_free(class_path);
   242 
   251 
   243     // Remove the prefixes
   252     return QHashableLatin1Literal::fromData(copy);
   244     path.remove(QLS("GtkWindow."));
       
   245     path.remove(QLS("GtkFixed."));
       
   246     return path;
       
   247 }
   253 }
   248 
   254 
   249 
   255 
   250 
   256 
   251 bool QGtkStyleFilter::eventFilter(QObject *obj, QEvent *e)
   257 bool QGtkStyleFilter::eventFilter(QObject *obj, QEvent *e)
   259     }
   265     }
   260     return QObject::eventFilter(obj, e);
   266     return QObject::eventFilter(obj, e);
   261 }
   267 }
   262 
   268 
   263 QList<QGtkStylePrivate *> QGtkStylePrivate::instances;
   269 QList<QGtkStylePrivate *> QGtkStylePrivate::instances;
       
   270 QGtkStylePrivate::WidgetMap *QGtkStylePrivate::widgetMap = 0;
   264 
   271 
   265 QGtkStylePrivate::QGtkStylePrivate()
   272 QGtkStylePrivate::QGtkStylePrivate()
   266   : QCleanlooksStylePrivate()
   273   : QCleanlooksStylePrivate()
   267   , filter(this)
   274   , filter(this)
   268 {
   275 {
   280     initGtkWidgets();
   287     initGtkWidgets();
   281     if (isThemeAvailable())
   288     if (isThemeAvailable())
   282         qApp->installEventFilter(&filter);
   289         qApp->installEventFilter(&filter);
   283 }
   290 }
   284 
   291 
   285 GtkWidget* QGtkStylePrivate::gtkWidget(const QString &path)
   292 GtkWidget* QGtkStylePrivate::gtkWidget(const QHashableLatin1Literal &path)
   286 {
   293 {
   287     GtkWidget *widget = gtkWidgetMap()->value(path);
   294     GtkWidget *widget = gtkWidgetMap()->value(path);
   288     if (!widget) {
   295     if (!widget) {
   289         // Theme might have rearranged widget internals
   296         // Theme might have rearranged widget internals
   290         widget = gtkWidgetMap()->value(path);
   297         widget = gtkWidgetMap()->value(path);
   291     }
   298     }
   292     return widget;
   299     return widget;
   293 }
   300 }
   294 
   301 
   295 GtkStyle* QGtkStylePrivate::gtkStyle(const QString &path)
   302 GtkStyle* QGtkStylePrivate::gtkStyle(const QHashableLatin1Literal &path)
   296 {
   303 {
   297     if (gtkWidgetMap()->contains(path))
   304     if (GtkWidget *w = gtkWidgetMap()->value(path))
   298         return gtkWidgetMap()->value(path)->style;
   305         return w->style;
   299     return 0;
   306     return 0;
   300 }
   307 }
   301 
   308 
   302 /*! \internal
   309 /*! \internal
   303  *  Get references to gtk functions after we dynamically load the library.
   310  *  Get references to gtk functions after we dynamically load the library.
   492                  "See http://www.gtk.org/setuid.html for more information.\n");
   499                  "See http://www.gtk.org/setuid.html for more information.\n");
   493         return;
   500         return;
   494     }
   501     }
   495 
   502 
   496     static QString themeName;
   503     static QString themeName;
   497     if (!gtkWidgetMap()->contains(QLS("GtkWindow")) && themeName.isEmpty()) {
   504     if (!gtkWidgetMap()->contains("GtkWindow") && themeName.isEmpty()) {
   498         themeName = getThemeName();
   505         themeName = getThemeName();
   499 
   506 
   500         if (themeName.isEmpty()) {
   507         if (themeName.isEmpty()) {
   501             qWarning("QGtkStyle was unable to detect the current GTK+ theme.");
   508             qWarning("QGtkStyle was unable to detect the current GTK+ theme.");
   502             return;
   509             return;
   517         // make a window
   524         // make a window
   518         GtkWidget* gtkWindow = QGtkStylePrivate::gtk_window_new(GTK_WINDOW_POPUP);
   525         GtkWidget* gtkWindow = QGtkStylePrivate::gtk_window_new(GTK_WINDOW_POPUP);
   519         QGtkStylePrivate::gtk_widget_realize(gtkWindow);
   526         QGtkStylePrivate::gtk_widget_realize(gtkWindow);
   520         if (displayDepth == -1)
   527         if (displayDepth == -1)
   521             displayDepth = QGtkStylePrivate::gdk_drawable_get_depth(gtkWindow->window);
   528             displayDepth = QGtkStylePrivate::gdk_drawable_get_depth(gtkWindow->window);
   522         gtkWidgetMap()->insert(QLS("GtkWindow"), gtkWindow);
   529         gtkWidgetMap()->insert(QHashableLatin1Literal::fromData(strdup("GtkWindow")), gtkWindow);
   523 
   530 
   524 
   531 
   525         // Make all other widgets. respect the text direction
   532         // Make all other widgets. respect the text direction
   526         if (qApp->layoutDirection() == Qt::RightToLeft)
   533         if (qApp->layoutDirection() == Qt::RightToLeft)
   527             QGtkStylePrivate::gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
   534             QGtkStylePrivate::gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
   528 
   535 
   529         if (!gtkWidgetMap()->contains(QLS("GtkButton"))) {
   536         if (!gtkWidgetMap()->contains("GtkButton")) {
   530             GtkWidget *gtkButton = QGtkStylePrivate::gtk_button_new();
   537             GtkWidget *gtkButton = QGtkStylePrivate::gtk_button_new();
   531             addWidget(gtkButton);
   538             addWidget(gtkButton);
   532             g_signal_connect(gtkButton, "style-set", G_CALLBACK(gtkStyleSetCallback), 0);
   539             g_signal_connect(gtkButton, "style-set", G_CALLBACK(gtkStyleSetCallback), 0);
   533             addWidget(QGtkStylePrivate::gtk_tool_button_new(NULL, "Qt"));
   540             addWidget(QGtkStylePrivate::gtk_tool_button_new(NULL, "Qt"));
   534             addWidget(QGtkStylePrivate::gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE));
   541             addWidget(QGtkStylePrivate::gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE));
   561         else // Rebuild map
   568         else // Rebuild map
   562         {
   569         {
   563             // When styles change subwidgets can get rearranged
   570             // When styles change subwidgets can get rearranged
   564             // as with the combo box. We need to update the widget map
   571             // as with the combo box. We need to update the widget map
   565             // to reflect this;
   572             // to reflect this;
   566             QHash<QString, GtkWidget*> oldMap = *gtkWidgetMap();
   573             QHash<QHashableLatin1Literal, GtkWidget*> oldMap = *gtkWidgetMap();
   567             gtkWidgetMap()->clear();
   574             gtkWidgetMap()->clear();
   568             QHashIterator<QString, GtkWidget*> it(oldMap);
   575             QHashIterator<QHashableLatin1Literal, GtkWidget*> it(oldMap);
   569             while (it.hasNext()) {
   576             while (it.hasNext()) {
   570                 it.next();
   577                 it.next();
   571                 if (!it.key().contains(QLatin1Char('.'))) {
   578                 if (!strchr(it.key().data(), '.')) {
   572                     addAllSubWidgets(it.value());
   579                     addAllSubWidgets(it.value());
   573                 }
   580                 }
   574             }
   581             }
   575         }
   582         }
   576     } else {
   583     } else {
   581 /*! \internal
   588 /*! \internal
   582  * destroys all previously buffered widgets.
   589  * destroys all previously buffered widgets.
   583  */
   590  */
   584 void QGtkStylePrivate::cleanupGtkWidgets()
   591 void QGtkStylePrivate::cleanupGtkWidgets()
   585 {
   592 {
   586     if (gtkWidgetMap()->contains(QLS("GtkWindow"))) // Gtk will destroy all children
   593     if (!widgetMap)
   587         gtk_widget_destroy(gtkWidgetMap()->value(QLS("GtkWindow")));
   594         return;
       
   595     if (widgetMap->contains("GtkWindow")) // Gtk will destroy all children
       
   596         gtk_widget_destroy(widgetMap->value("GtkWindow"));
       
   597     for (QHash<QHashableLatin1Literal, GtkWidget *>::const_iterator it = widgetMap->constBegin();
       
   598          it != widgetMap->constEnd(); ++it)
       
   599         free(const_cast<char *>(it.key().data()));
   588 }
   600 }
   589 
   601 
   590 static bool resolveGConf()
   602 static bool resolveGConf()
   591 {
   603 {
   592     if (!QGtkStylePrivate::gconf_client_get_default) {
   604     if (!QGtkStylePrivate::gconf_client_get_default) {
   673 
   685 
   674 // Get size of the arrow controls in a GtkSpinButton
   686 // Get size of the arrow controls in a GtkSpinButton
   675 int QGtkStylePrivate::getSpinboxArrowSize() const
   687 int QGtkStylePrivate::getSpinboxArrowSize() const
   676 {
   688 {
   677     const int MIN_ARROW_WIDTH = 6;
   689     const int MIN_ARROW_WIDTH = 6;
   678     GtkWidget *spinButton = gtkWidget(QLS("GtkSpinButton"));
   690     GtkWidget *spinButton = gtkWidget("GtkSpinButton");
   679     GtkStyle *style = spinButton->style;
   691     GtkStyle *style = spinButton->style;
   680     gint size = pango_font_description_get_size (style->font_desc);
   692     gint size = pango_font_description_get_size (style->font_desc);
   681     gint arrow_size;
   693     gint arrow_size;
   682     arrow_size = qMax(PANGO_PIXELS (size), MIN_ARROW_WIDTH) + style->xthickness;
   694     arrow_size = qMax(PANGO_PIXELS (size), MIN_ARROW_WIDTH) + style->xthickness;
   683     arrow_size += arrow_size%2 + 1;
   695     arrow_size += arrow_size%2 + 1;
   693     return (version == 4);
   705     return (version == 4);
   694 }
   706 }
   695 
   707 
   696 void QGtkStylePrivate::applyCustomPaletteHash()
   708 void QGtkStylePrivate::applyCustomPaletteHash()
   697 {
   709 {
   698     QPalette menuPal = gtkWidgetPalette(QLS("GtkMenu"));
   710     QPalette menuPal = gtkWidgetPalette("GtkMenu");
   699     GdkColor gdkBg = gtkWidget(QLS("GtkMenu"))->style->bg[GTK_STATE_NORMAL];
   711     GdkColor gdkBg = gtkWidget("GtkMenu")->style->bg[GTK_STATE_NORMAL];
   700     QColor bgColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
   712     QColor bgColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
   701     menuPal.setBrush(QPalette::Base, bgColor);
   713     menuPal.setBrush(QPalette::Base, bgColor);
   702     menuPal.setBrush(QPalette::Window, bgColor);
   714     menuPal.setBrush(QPalette::Window, bgColor);
   703     qApp->setPalette(menuPal, "QMenu");
   715     qApp->setPalette(menuPal, "QMenu");
   704 
   716 
   705     QPalette toolbarPal = gtkWidgetPalette(QLS("GtkToolbar"));
   717     QPalette toolbarPal = gtkWidgetPalette("GtkToolbar");
   706     qApp->setPalette(toolbarPal, "QToolBar");
   718     qApp->setPalette(toolbarPal, "QToolBar");
   707 
   719 
   708     QPalette menuBarPal = gtkWidgetPalette(QLS("GtkMenuBar"));
   720     QPalette menuBarPal = gtkWidgetPalette("GtkMenuBar");
   709     qApp->setPalette(menuBarPal, "QMenuBar");
   721     qApp->setPalette(menuBarPal, "QMenuBar");
   710 }
   722 }
   711 
   723 
   712 /*! \internal
   724 /*! \internal
   713  *  Returns the gtk Widget that should be used to determine text foreground and background colors.
   725  *  Returns the gtk Widget that should be used to determine text foreground and background colors.
   714 */
   726 */
   715 GtkWidget* QGtkStylePrivate::getTextColorWidget() const
   727 GtkWidget* QGtkStylePrivate::getTextColorWidget() const
   716 {
   728 {
   717     return  gtkWidget(QLS("GtkEntry"));
   729     return  gtkWidget("GtkEntry");
   718 }
   730 }
   719 
   731 
   720 void QGtkStylePrivate::setupGtkWidget(GtkWidget* widget)
   732 void QGtkStylePrivate::setupGtkWidget(GtkWidget* widget)
   721 {
   733 {
   722     if (Q_GTK_IS_WIDGET(widget)) {
   734     if (Q_GTK_IS_WIDGET(widget)) {
   723         static GtkWidget* protoLayout = 0;
   735         static GtkWidget* protoLayout = 0;
   724         if (!protoLayout) {
   736         if (!protoLayout) {
   725             protoLayout = QGtkStylePrivate::gtk_fixed_new();
   737             protoLayout = QGtkStylePrivate::gtk_fixed_new();
   726             QGtkStylePrivate::gtk_container_add((GtkContainer*)(gtkWidgetMap()->value(QLS("GtkWindow"))), protoLayout);
   738             QGtkStylePrivate::gtk_container_add((GtkContainer*)(gtkWidgetMap()->value("GtkWindow")), protoLayout);
   727         }
   739         }
   728         Q_ASSERT(protoLayout);
   740         Q_ASSERT(protoLayout);
   729 
   741 
   730         if (!widget->parent && !GTK_WIDGET_TOPLEVEL(widget))
   742         if (!widget->parent && !GTK_WIDGET_TOPLEVEL(widget))
   731             QGtkStylePrivate::gtk_container_add((GtkContainer*)(protoLayout), widget);
   743             QGtkStylePrivate::gtk_container_add((GtkContainer*)(protoLayout), widget);
   734 }
   746 }
   735 
   747 
   736 void QGtkStylePrivate::addWidgetToMap(GtkWidget *widget)
   748 void QGtkStylePrivate::addWidgetToMap(GtkWidget *widget)
   737 {
   749 {
   738     if (Q_GTK_IS_WIDGET(widget)) {
   750     if (Q_GTK_IS_WIDGET(widget)) {
   739        gtk_widget_realize(widget);
   751         gtk_widget_realize(widget);
   740        gtkWidgetMap()->insert(classPath(widget), widget);
   752         QHashableLatin1Literal widgetPath = classPath(widget);
       
   753 
       
   754         WidgetMap *map = gtkWidgetMap();
       
   755         WidgetMap::iterator it = map->find(widgetPath);
       
   756         if (it != map->end()) {
       
   757             free(const_cast<char *>(it.key().data()));
       
   758             map->erase(it);
       
   759         }
       
   760         map->insert(widgetPath, widget);
       
   761 #ifdef DUMP_GTK_WIDGET_TREE
       
   762         qWarning("Inserted Gtk Widget: %s", widgetPath.data());
       
   763 #endif
   741     }
   764     }
   742  }
   765  }
   743 
   766 
   744 void QGtkStylePrivate::addAllSubWidgets(GtkWidget *widget, gpointer v)
   767 void QGtkStylePrivate::addAllSubWidgets(GtkWidget *widget, gpointer v)
   745 {
   768 {
   748     if (GTK_CHECK_TYPE ((widget), gtk_container_get_type()))
   771     if (GTK_CHECK_TYPE ((widget), gtk_container_get_type()))
   749         gtk_container_forall((GtkContainer*)widget, addAllSubWidgets, NULL);
   772         gtk_container_forall((GtkContainer*)widget, addAllSubWidgets, NULL);
   750 }
   773 }
   751 
   774 
   752 // Updates window/windowtext palette based on the indicated gtk widget
   775 // Updates window/windowtext palette based on the indicated gtk widget
   753 QPalette QGtkStylePrivate::gtkWidgetPalette(const QString &gtkWidgetName) const
   776 QPalette QGtkStylePrivate::gtkWidgetPalette(const QHashableLatin1Literal &gtkWidgetName) const
   754 {
   777 {
   755     GtkWidget *gtkWidget = QGtkStylePrivate::gtkWidget(gtkWidgetName);
   778     GtkWidget *gtkWidget = QGtkStylePrivate::gtkWidget(gtkWidgetName);
   756     Q_ASSERT(gtkWidget);
   779     Q_ASSERT(gtkWidget);
   757     QPalette pal = QApplication::palette();
   780     QPalette pal = QApplication::palette();
   758     GdkColor gdkBg = gtkWidget->style->bg[GTK_STATE_NORMAL];
   781     GdkColor gdkBg = gtkWidget->style->bg[GTK_STATE_NORMAL];
  1084         return QIcon::fromTheme(iconName);
  1107         return QIcon::fromTheme(iconName);
  1085     }
  1108     }
  1086     return icon;
  1109     return icon;
  1087 }
  1110 }
  1088 
  1111 
       
  1112 bool operator==(const QHashableLatin1Literal &l1, const QHashableLatin1Literal &l2)
       
  1113 {
       
  1114     return l1.size() == l2.size() || qstrcmp(l1.data(), l2.data()) == 0;
       
  1115 }
       
  1116 
       
  1117 // copied from qHash.cpp
       
  1118 uint qHash(const QHashableLatin1Literal &key)
       
  1119 {
       
  1120     int n = key.size();
       
  1121     const uchar *p = reinterpret_cast<const uchar *>(key.data());
       
  1122     uint h = 0;
       
  1123     uint g;
       
  1124 
       
  1125     while (n--) {
       
  1126         h = (h << 4) + *p++;
       
  1127         if ((g = (h & 0xf0000000)) != 0)
       
  1128             h ^= g >> 23;
       
  1129         h &= ~g;
       
  1130     }
       
  1131     return h;
       
  1132 }
       
  1133 
  1089 QT_END_NAMESPACE
  1134 QT_END_NAMESPACE
  1090 
  1135 
  1091 #endif // !defined(QT_NO_STYLE_GTK)
  1136 #endif // !defined(QT_NO_STYLE_GTK)