diff --git a/app/dialogs/about-dialog.c b/app/dialogs/about-dialog.c index 74cba08ae0..e7ff0a7b38 100644 --- a/app/dialogs/about-dialog.c +++ b/app/dialogs/about-dialog.c @@ -30,6 +30,8 @@ #include "config/gimpcoreconfig.h" +#include "widgets/gimpwidgets-utils.h" + #include "about.h" #include "git-version.h" @@ -50,23 +52,25 @@ typedef struct { - GtkWidget *dialog; + GtkWidget *dialog; + + Gimp *gimp; GtkWidget *update_frame; GimpCoreConfig *config; - GtkWidget *anim_area; - PangoLayout *layout; + GtkWidget *anim_area; + PangoLayout *layout; - gint n_authors; - gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */ + gint n_authors; + gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */ - guint timer; + guint timer; - gint index; - gint animstep; - gint state; - gboolean visible; + gint index; + gint animstep; + gint state; + gboolean visible; } GimpAboutDialog; @@ -99,7 +103,8 @@ static void about_dialog_download_clicked const gchar *link); GtkWidget * -about_dialog_create (GimpCoreConfig *config) +about_dialog_create (Gimp *gimp, + GimpCoreConfig *config) { static GimpAboutDialog dialog; @@ -112,6 +117,7 @@ about_dialog_create (GimpCoreConfig *config) gchar *copyright; gchar *version; + dialog.gimp = gimp; dialog.n_authors = G_N_ELEMENTS (authors) - 1; dialog.config = config; @@ -206,6 +212,10 @@ about_dialog_map (GtkWidget *widget, dialog->timer = g_timeout_add (800, about_dialog_timer, dialog); } + +#ifdef G_OS_WIN32 + gimp_window_set_title_bar_theme (dialog->gimp, widget, FALSE); +#endif } static void diff --git a/app/dialogs/about-dialog.h b/app/dialogs/about-dialog.h index 516d7da500..0a929cbe24 100644 --- a/app/dialogs/about-dialog.h +++ b/app/dialogs/about-dialog.h @@ -19,7 +19,8 @@ #define __ABOUT_DIALOG_H__ -GtkWidget * about_dialog_create (GimpCoreConfig *config); +GtkWidget * about_dialog_create (Gimp *gimp, + GimpCoreConfig *config); #endif /* __ABOUT_DIALOG_H__ */ diff --git a/app/dialogs/dialogs-constructors.c b/app/dialogs/dialogs-constructors.c index af9f72719f..99c0ffca29 100644 --- a/app/dialogs/dialogs-constructors.c +++ b/app/dialogs/dialogs-constructors.c @@ -217,7 +217,7 @@ dialogs_about_get (GimpDialogFactory *factory, GimpUIManager *ui_manager, gint view_size) { - return about_dialog_create (context->gimp->edit_config); + return about_dialog_create (context->gimp, context->gimp->edit_config); } GtkWidget * diff --git a/app/gimp-update.c b/app/gimp-update.c index 520b6d1c75..7aa289efe6 100644 --- a/app/gimp-update.c +++ b/app/gimp-update.c @@ -435,14 +435,18 @@ gimp_update_about_dialog (GimpCoreConfig *config, const GParamSpec *pspec, gpointer user_data) { +#ifndef GIMP_CONSOLE_COMPILATION + Gimp *gimp = user_data; +#endif + g_signal_handlers_disconnect_by_func (config, (GCallback) gimp_update_about_dialog, - NULL); + user_data); if (config->last_known_release != NULL) { #ifndef GIMP_CONSOLE_COMPILATION - gtk_widget_show (about_dialog_create (config)); + gtk_widget_show (about_dialog_create (gimp, config)); #else g_printerr (_("A new version of GIMP (%s) was released.\n" "It is recommended to update."), @@ -639,7 +643,7 @@ gimp_update_auto_check (GimpCoreConfig *config, g_signal_connect (config, "notify::last-known-release", (GCallback) gimp_update_about_dialog, - NULL); + gimp); gimp_update_check (config); diff --git a/app/gui/gui.c b/app/gui/gui.c index 5e34b96f41..54c086254e 100644 --- a/app/gui/gui.c +++ b/app/gui/gui.c @@ -617,6 +617,10 @@ gui_restore_after_callback (Gimp *gimp, shell = gimp_display_get_shell (display); +#ifdef G_OS_WIN32 + themes_set_title_bar (gimp); +#endif + if (gui_config->restore_session) session_restore (gimp, initial_monitor); @@ -624,7 +628,7 @@ gui_restore_after_callback (Gimp *gimp, #ifdef G_OS_WIN32 /* Prevents window from reappearing on start-up if the user - * requested it to be minimized via window hints + * requested it to be minimized via window hints */ if (StartupInfo.wShowWindow != SW_SHOWMINIMIZED && StartupInfo.wShowWindow != SW_SHOWMINNOACTIVE && diff --git a/app/gui/themes.c b/app/gui/themes.c index b45e035013..950b27a6dd 100644 --- a/app/gui/themes.c +++ b/app/gui/themes.c @@ -31,6 +31,10 @@ #include "core/gimp.h" +#include "display/gimpimagewindow.h" + +#include "widgets/gimpwidgets-utils.h" + #include "themes.h" #include "gimp-intl.h" @@ -105,6 +109,10 @@ themes_init (Gimp *gimp) gimp); themes_theme_change_notify (config, NULL, gimp); + +#ifdef G_OS_WIN32 + themes_set_title_bar (gimp); +#endif } void @@ -469,6 +477,10 @@ themes_theme_change_notify (GimpGuiConfig *config, g_object_unref (theme_css); gtk_style_context_reset_widgets (gdk_screen_get_default ()); + +#ifdef G_OS_WIN32 + themes_set_title_bar (gimp); +#endif } static void @@ -549,3 +561,22 @@ themes_theme_paths_notify (GimpExtensionManager *manager, g_list_free_full (path, (GDestroyNotify) g_object_unref); } } + +void +themes_set_title_bar (Gimp *gimp) +{ +#ifdef G_OS_WIN32 + GList *windows = gimp_get_image_windows (gimp); + GList *iter; + + for (iter = windows; iter; iter = g_list_next (iter)) + { + GtkWidget *window = GTK_WIDGET (windows->data); + + gimp_window_set_title_bar_theme (gimp, window, TRUE); + } + + if (windows) + g_list_free (windows); +#endif +} diff --git a/app/gui/themes.h b/app/gui/themes.h index 0b7e74fc76..87682ed82f 100644 --- a/app/gui/themes.h +++ b/app/gui/themes.h @@ -30,5 +30,6 @@ GFile * themes_get_theme_file (Gimp *gimp, const gchar *first_component, ...) G_GNUC_NULL_TERMINATED; +void themes_set_title_bar (Gimp *gimp); #endif /* __THEMES_H__ */ diff --git a/app/widgets/gimpfiledialog.c b/app/widgets/gimpfiledialog.c index d01d32a8a3..84cfa2b614 100644 --- a/app/widgets/gimpfiledialog.c +++ b/app/widgets/gimpfiledialog.c @@ -86,6 +86,8 @@ static gboolean gimp_file_dialog_delete_event (GtkWidget *w GdkEventAny *event); static void gimp_file_dialog_response (GtkDialog *dialog, gint response_id); +static void gimp_file_dialog_map (GimpFileDialog *dialog, + gpointer data); static GFile * gimp_file_dialog_real_get_default_folder (GimpFileDialog *dialog); static void gimp_file_dialog_real_save_state (GimpFileDialog *dialog, const gchar *state_name); @@ -225,6 +227,11 @@ gimp_file_dialog_class_init (GimpFileDialogClass *klass) static void gimp_file_dialog_init (GimpFileDialog *dialog) { +#ifdef G_OS_WIN32 + g_signal_connect (dialog, "map", + G_CALLBACK (gimp_file_dialog_map), + NULL); +#endif } static void @@ -420,6 +427,15 @@ gimp_file_dialog_response (GtkDialog *dialog, } } +static void +gimp_file_dialog_map (GimpFileDialog *dialog, + gpointer data) +{ +#ifdef G_OS_WIN32 + gimp_window_set_title_bar_theme (dialog->gimp, GTK_WIDGET (dialog), FALSE); +#endif +} + static GFile * gimp_file_dialog_real_get_default_folder (GimpFileDialog *dialog) { diff --git a/app/widgets/gimpwidgets-utils.c b/app/widgets/gimpwidgets-utils.c index dd587e2f22..e7298eaf97 100644 --- a/app/widgets/gimpwidgets-utils.c +++ b/app/widgets/gimpwidgets-utils.c @@ -26,7 +26,12 @@ #include #ifdef GDK_WINDOWING_WIN32 +#include #include + +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif #endif #ifdef GDK_WINDOWING_X11 @@ -51,6 +56,8 @@ #include "gegl/gimp-babl.h" +#include "config/gimpguiconfig.h" + #include "core/gimp.h" #include "core/gimpprogress.h" #include "core/gimptoolinfo.h" @@ -2616,3 +2623,59 @@ gimp_window_set_transient_cb (GtkWidget *window, } #endif } + +void +gimp_window_set_title_bar_theme (Gimp *gimp, + GtkWidget *dialog, + gboolean is_main_window) +{ +#ifdef G_OS_WIN32 + HWND hwnd; + GdkWindow *window = NULL; + gboolean use_dark_mode = FALSE; + + window = gtk_widget_get_window (GTK_WIDGET (dialog)); + if (window) + { + if (gimp) + { + GimpGuiConfig *config; + + config = GIMP_GUI_CONFIG (gimp->config); + use_dark_mode = config->prefer_dark_theme; + } + else + { + GtkStyleContext *style; + GdkRGBA *color = NULL; + + /* Workaround if we don't have access to GimpGuiConfig. + * If the background color is below the threshold, then we're + * likely in dark mode. + */ + style = gtk_widget_get_style_context (dialog); + gtk_style_context_get (style, gtk_style_context_get_state (style), + GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color, + NULL); + if (color) + { + if (color->red < 0.5 && color->green < 0.5 && color->blue < 0.5) + use_dark_mode = TRUE; + + gdk_rgba_free (color); + } + } + + hwnd = (HWND) gdk_win32_window_get_handle (window); + DwmSetWindowAttribute (hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, + &use_dark_mode, sizeof (use_dark_mode)); + + if (! is_main_window) + { + /* Toggle the window's visibility so the title bar change appears */ + gdk_window_hide (window); + gdk_window_show (window); + } + } +#endif +} diff --git a/app/widgets/gimpwidgets-utils.h b/app/widgets/gimpwidgets-utils.h index 114bb11146..eb1bd3d3d6 100644 --- a/app/widgets/gimpwidgets-utils.h +++ b/app/widgets/gimpwidgets-utils.h @@ -165,5 +165,9 @@ gboolean gimp_utils_are_menu_path_identical (const gchar *path1 gchar **mnemonic_path1, gchar **path1_section_name); +void gimp_window_set_title_bar_theme (Gimp *gimp, + GtkWidget *dialog, + gboolean is_main_window); + #endif /* __APP_GIMP_WIDGETS_UTILS_H__ */ diff --git a/libgimpwidgets/gimpdialog.c b/libgimpwidgets/gimpdialog.c index 77f4199cf2..3f2d8eb290 100644 --- a/libgimpwidgets/gimpdialog.c +++ b/libgimpwidgets/gimpdialog.c @@ -34,6 +34,14 @@ #include "libgimp/libgimp-intl.h" +#ifdef G_OS_WIN32 +#include +#include + +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif +#endif /** * SECTION: gimpdialog @@ -67,27 +75,28 @@ struct _GimpDialogPrivate #define GET_PRIVATE(obj) (((GimpDialog *) (obj))->priv) -static void gimp_dialog_constructed (GObject *object); -static void gimp_dialog_dispose (GObject *object); -static void gimp_dialog_finalize (GObject *object); -static void gimp_dialog_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_dialog_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); +static void gimp_dialog_constructed (GObject *object); +static void gimp_dialog_dispose (GObject *object); +static void gimp_dialog_finalize (GObject *object); +static void gimp_dialog_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_dialog_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); -static void gimp_dialog_hide (GtkWidget *widget); -static gboolean gimp_dialog_delete_event (GtkWidget *widget, - GdkEventAny *event); +static void gimp_dialog_hide (GtkWidget *widget); +static gboolean gimp_dialog_delete_event (GtkWidget *widget, + GdkEventAny *event); -static void gimp_dialog_close (GtkDialog *dialog); +static void gimp_dialog_close (GtkDialog *dialog); -static void gimp_dialog_response (GtkDialog *dialog, - gint response_id); +static void gimp_dialog_response (GtkDialog *dialog, + gint response_id); +static void gimp_dialog_set_title_bar_theme (GtkWidget *dialog); G_DEFINE_TYPE_WITH_PRIVATE (GimpDialog, gimp_dialog, GTK_TYPE_DIALOG) @@ -161,6 +170,12 @@ gimp_dialog_init (GimpDialog *dialog) g_signal_connect (dialog, "response", G_CALLBACK (gimp_dialog_response), NULL); + +#ifdef G_OS_WIN32 + g_signal_connect (GTK_WIDGET (dialog), "map", + G_CALLBACK (gimp_dialog_set_title_bar_theme), + NULL); +#endif } static void @@ -656,6 +671,10 @@ gimp_dialog_run (GimpDialog *dialog) gtk_window_present (GTK_WINDOW (dialog)); +#ifdef G_OS_WIN32 + gimp_dialog_set_title_bar_theme (GTK_WIDGET (dialog)); +#endif + response_handler = g_signal_connect (dialog, "response", G_CALLBACK (run_response_handler), &ri); @@ -750,3 +769,46 @@ gimp_dialogs_show_help_button (gboolean show) { show_help_button = show ? TRUE : FALSE; } + +void +gimp_dialog_set_title_bar_theme (GtkWidget *dialog) +{ +#ifdef G_OS_WIN32 + HWND hwnd; + gboolean use_dark_mode = FALSE; + GdkWindow *window = NULL; + + window = gtk_widget_get_window (GTK_WIDGET (dialog)); + if (window) + { + GtkStyleContext *style; + GdkRGBA *color = NULL; + + hwnd = (HWND) gdk_win32_window_get_handle (window); + /* Workaround since we don't have access to GimpGuiConfig. + * If the background color is below the threshold, then we're + * likely in dark mode. + */ + style = gtk_widget_get_style_context (GTK_WIDGET (dialog)); + gtk_style_context_get (style, gtk_style_context_get_state (style), + GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color, + NULL); + if (color) + { + if (color->red < 0.5 && color->green < 0.5 && color->blue < 0.5) + use_dark_mode = TRUE; + + gdk_rgba_free (color); + } + + DwmSetWindowAttribute (hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, + &use_dark_mode, sizeof (use_dark_mode)); + UpdateWindow (hwnd); + ShowWindow (hwnd, 5); + + /* Toggle the window's visibility so the title bar change appears */ + gdk_window_hide (window); + gdk_window_show (window); + } +#endif +}