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) |
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 >kWidgetName) const |
776 QPalette QGtkStylePrivate::gtkWidgetPalette(const QHashableLatin1Literal >kWidgetName) 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]; |