GNU bug report logs -
#79689
Make Emacs pure GTK respect GTK dark mode settings
Previous Next
To reply to this bug, email your comments to 79689 AT debbugs.gnu.org.
There is no need to reopen the bug first.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Fri, 24 Oct 2025 05:35:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Ahmed Khanzada <me <at> enzu.ru>:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org.
(Fri, 24 Oct 2025 05:35:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Emacs, as a "pure GTK" application, should respect dark mode settings
when coloring its GTK title bar and GTK widgets.
This is particularly important on GNOME.
This patch allows a "pure GTK" Emacs to toggle its GTK title bar and GTK
widgets between dark and light modes, based on what is set by the
desktop environment (or alternative methods). I believe a similar
feature already exists for Emacs on Windows.
It will check on initialization, and also change whenever the system
setting changes.
Some notes:
- I am not an expert in GObject or the Emacs C internals, but I tried my
best to copy the patterns that I already found
- I don't know how much of this code could or should apply to regular
GTK Emacs (for instance, GTK handles title bars on Wayland but not X11)
- I used the C preprocessor to hide PGTK code, but not entire functions
- I dislike xg_set_initial_dark_mode at the end of frame creation, but
that's the only way it worked for me on init
- If I am the first person to make gtkutil.c depend upon xsettings.h,
maybe I didn't place things in the correct spots
I hope this patch helps. I have attached pictures of how Emacs looks
with dark and light GTK title bars and widgets respectively.
Thanks,
Ahmed
[gtk-dark-mode.patch (text/x-patch, attachment)]
[screenshot-dark-mode.png (image/png, attachment)]
[screenshot-light-mode.png (image/png, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Fri, 24 Oct 2025 07:10:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 79689 <at> debbugs.gnu.org (full text, mbox):
> Date: Thu, 23 Oct 2025 22:34:28 -0700
> From: Ahmed Khanzada <me <at> enzu.ru>
>
> Emacs, as a "pure GTK" application, should respect dark mode settings
> when coloring its GTK title bar and GTK widgets.
>
> This is particularly important on GNOME.
>
> This patch allows a "pure GTK" Emacs to toggle its GTK title bar and GTK
> widgets between dark and light modes, based on what is set by the
> desktop environment (or alternative methods). I believe a similar
> feature already exists for Emacs on Windows.
>
> It will check on initialization, and also change whenever the system
> setting changes.
>
> Some notes:
>
> - I am not an expert in GObject or the Emacs C internals, but I tried my
> best to copy the patterns that I already found
>
> - I don't know how much of this code could or should apply to regular
> GTK Emacs (for instance, GTK handles title bars on Wayland but not X11)
>
> - I used the C preprocessor to hide PGTK code, but not entire functions
>
> - I dislike xg_set_initial_dark_mode at the end of frame creation, but
> that's the only way it worked for me on init
>
> - If I am the first person to make gtkutil.c depend upon xsettings.h,
> maybe I didn't place things in the correct spots
>
> I hope this patch helps. I have attached pictures of how Emacs looks
> with dark and light GTK title bars and widgets respectively.
Thanks. Could you please submit the patch in "git format-patch"
format, including commit log messages in the form according to our
conventions (see CONTRIBUTE)?
Also, this changeset needs a NEWS entry describing the new feature.
Po Lu, any comments or suggestions?
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Fri, 24 Oct 2025 17:17:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 79689 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Here's a cleaned up patch file using "git format-patch -1" with a NEWS
entry.
On 10/24/25 12:09 AM, Eli Zaretskii wrote:
>> Date: Thu, 23 Oct 2025 22:34:28 -0700
>> From: Ahmed Khanzada <me <at> enzu.ru>
>>
>> Emacs, as a "pure GTK" application, should respect dark mode settings
>> when coloring its GTK title bar and GTK widgets.
>>
>> This is particularly important on GNOME.
>>
>> This patch allows a "pure GTK" Emacs to toggle its GTK title bar and GTK
>> widgets between dark and light modes, based on what is set by the
>> desktop environment (or alternative methods). I believe a similar
>> feature already exists for Emacs on Windows.
>>
>> It will check on initialization, and also change whenever the system
>> setting changes.
>>
>> Some notes:
>>
>> - I am not an expert in GObject or the Emacs C internals, but I tried my
>> best to copy the patterns that I already found
>>
>> - I don't know how much of this code could or should apply to regular
>> GTK Emacs (for instance, GTK handles title bars on Wayland but not X11)
>>
>> - I used the C preprocessor to hide PGTK code, but not entire functions
>>
>> - I dislike xg_set_initial_dark_mode at the end of frame creation, but
>> that's the only way it worked for me on init
>>
>> - If I am the first person to make gtkutil.c depend upon xsettings.h,
>> maybe I didn't place things in the correct spots
>>
>> I hope this patch helps. I have attached pictures of how Emacs looks
>> with dark and light GTK title bars and widgets respectively.
> Thanks. Could you please submit the patch in "git format-patch"
> format, including commit log messages in the form according to our
> conventions (see CONTRIBUTE)?
>
> Also, this changeset needs a NEWS entry describing the new feature.
>
> Po Lu, any comments or suggestions?
[0001-Automatically-toggle-between-dark-and-light-mode-PGT.patch (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sat, 25 Oct 2025 01:02:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 79689 <at> debbugs.gnu.org (full text, mbox):
Ahmed Khanzada <me <at> enzu.ru> writes:
> From 743f10835fe5b81b9d3816c42a75ad15d2133ba3 Mon Sep 17 00:00:00 2001
> From: Ahmed Khanzada <me <at> enzu.ru>
> Date: Fri, 24 Oct 2025 10:10:40 -0700
> Subject: [PATCH] Automatically toggle between dark and light mode PGTK widgets
>
> ---
> etc/NEWS | 6 ++++++
> src/gtkutil.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
> src/gtkutil.h | 3 +++
> src/xsettings.c | 46 +++++++++++++++++++++++++++++++++++++++++
> src/xsettings.h | 1 +
> 5 files changed, 110 insertions(+)
>
> diff --git a/etc/NEWS b/etc/NEWS
> index 1bfdc326a66..8b3e588ffbd 100644
> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -3378,6 +3378,12 @@ This is an abbreviation for using the name of the keymap as the prefix
> command name. E.g., '(defvar-keymap foo-map :prefix t)' is equivalent
> to '(defvar-keymap foo-map :prefix 'foo-map)'.
>
> ++++
> +** Emacs PGTK toolkit respects dark and light modes
> +Emacs when built with the pure GTK toolkit now respects desktop
> +dark and light modes for drawing a GTK toolbar and widgets,
> +automatically toggling between them.
> +
>
> * Changes in Emacs 31.1 on Non-Free Operating Systems
>
> diff --git a/src/gtkutil.c b/src/gtkutil.c
> index c192102730c..652308f01ec 100644
> --- a/src/gtkutil.c
> +++ b/src/gtkutil.c
> @@ -30,6 +30,7 @@ Copyright (C) 2003-2025 Free Software Foundation, Inc.
> #include "dispextern.h"
> #include "frame.h"
> #include "systime.h"
> +#include "xsettings.h"
> #ifndef HAVE_PGTK
> #include "xterm.h"
> #define xp x
> @@ -1450,6 +1451,57 @@ xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
> #endif
> }
>
> +/* Apply dark mode preference to GTK window decorations. */
> +
> +void
> +xg_set_gtk_theme_dark_mode (struct frame *f, bool dark_mode_p)
> +{
> +#ifdef HAVE_PGTK
> + GtkWidget *widget = FRAME_GTK_OUTER_WIDGET (f);
> + if (widget && GTK_IS_WINDOW (widget))
> + {
> + GtkSettings *settings = gtk_widget_get_settings (widget);
> + if (settings)
> + {
> + g_object_set (settings, "gtk-application-prefer-dark-theme",
> + dark_mode_p ? TRUE : FALSE, NULL);
> + }
> + }
> +#endif
> +}
Thanks. I suggest not defining functions that only produce an effect on
PGTK on other GTK configurations, not least on GTK+ 2.x, where these
stylistic preferences do not exist at all.
> +/* Update all frames' dark mode based on system setting. */
> +
> +void
> +xg_update_dark_mode_for_all_frames (bool dark_mode_p)
> +{
> +#ifdef HAVE_PGTK
> + struct frame *f;
> + Lisp_Object tail, frame;
> +
> + /* Only update frames if the frame list is initialized */
> + if (NILP (Vframe_list))
> + return;
This test is unnecessary as the frame list will always be initialized by
the time it is possible for settings callbacks to be invoked.
> + FOR_EACH_FRAME (tail, frame)
> + {
> + f = XFRAME (frame);
> + if (f && FRAME_GTK_WIDGET (f) && FRAME_GTK_OUTER_WIDGET (f))
These macros are not valid for non-GUI frames, which you must detect
with `FRAME_PGTK_P (f)'.
> + xg_set_gtk_theme_dark_mode (f, dark_mode_p);
> + }
> +#endif
> +}
> +
> +/* Set initial dark mode for a new frame (called during frame creation). */
> +void
> +xg_set_initial_dark_mode (struct frame *f)
> +{
> +#ifdef HAVE_PGTK
> + bool dark_mode_p = xg_get_system_dark_mode ();
> + xg_set_gtk_theme_dark_mode (f, dark_mode_p);
> +#endif
> +}
Ditto. Furthermore, it is redundant to iterate over each active frame
rather than every display connection's GdkScreen, to which GtkSettings
objects are specific:
struct pgtk_display_info *dpyinfo;
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
{
GdkScreen *screen
= gdk_display_get_default_screen (dpyinfo->gdpy);
GtkSettings *settings
= gtk_settings_get_for_screen (screen);
[...]
}
> +extern void xg_set_gtk_theme_dark_mode (struct frame *f, bool dark_mode_p);
> +extern void xg_update_dark_mode_for_all_frames (bool dark_mode_p);
> +extern void xg_set_initial_dark_mode (struct frame *f);
[...]
> +extern bool xg_get_system_dark_mode (void);
> #endif /* XSETTINGS_H */
These functions should not be declared when !HAVE_PGTK.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sat, 25 Oct 2025 07:23:03 GMT)
Full text and
rfc822 format available.
Message #17 received at 79689 <at> debbugs.gnu.org (full text, mbox):
> Date: Fri, 24 Oct 2025 10:15:52 -0700
> Cc: 79689 <at> debbugs.gnu.org
> From: Ahmed Khanzada <me <at> enzu.ru>
>
> Here's a cleaned up patch file using "git format-patch -1" with a NEWS
> entry.
Thanks, a few minor comments below.
> From 743f10835fe5b81b9d3816c42a75ad15d2133ba3 Mon Sep 17 00:00:00 2001
> From: Ahmed Khanzada <me <at> enzu.ru>
> Date: Fri, 24 Oct 2025 10:10:40 -0700
> Subject: [PATCH] Automatically toggle between dark and light mode PGTK widgets
This lacks the commit log entry, which should list the files and
functions/variables where you made changes. See "git log" for how we
format these log messages.
> ++++
The "+++" here means that the manuals were updated. But in this case,
there's nothing to update in the manuals, so please use "---" instead.
(The beginning of NEWS explains these conventions.)
> +** Emacs PGTK toolkit respects dark and light modes
The heading lines in NEWS should end with a period.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sun, 26 Oct 2025 05:44:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 79689 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Thanks for all the feedback. Here's another patch addressing both of
your recent feedback.
On 10/24/25 6:00 PM, Po Lu wrote:
> Ahmed Khanzada <me <at> enzu.ru> writes:
>
>> From 743f10835fe5b81b9d3816c42a75ad15d2133ba3 Mon Sep 17 00:00:00 2001
>> From: Ahmed Khanzada <me <at> enzu.ru>
>> Date: Fri, 24 Oct 2025 10:10:40 -0700
>> Subject: [PATCH] Automatically toggle between dark and light mode PGTK widgets
>>
>> ---
>> etc/NEWS | 6 ++++++
>> src/gtkutil.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
>> src/gtkutil.h | 3 +++
>> src/xsettings.c | 46 +++++++++++++++++++++++++++++++++++++++++
>> src/xsettings.h | 1 +
>> 5 files changed, 110 insertions(+)
>>
>> diff --git a/etc/NEWS b/etc/NEWS
>> index 1bfdc326a66..8b3e588ffbd 100644
>> --- a/etc/NEWS
>> +++ b/etc/NEWS
>> @@ -3378,6 +3378,12 @@ This is an abbreviation for using the name of the keymap as the prefix
>> command name. E.g., '(defvar-keymap foo-map :prefix t)' is equivalent
>> to '(defvar-keymap foo-map :prefix 'foo-map)'.
>>
>> ++++
>> +** Emacs PGTK toolkit respects dark and light modes
>> +Emacs when built with the pure GTK toolkit now respects desktop
>> +dark and light modes for drawing a GTK toolbar and widgets,
>> +automatically toggling between them.
>> +
>>
>> * Changes in Emacs 31.1 on Non-Free Operating Systems
>>
>> diff --git a/src/gtkutil.c b/src/gtkutil.c
>> index c192102730c..652308f01ec 100644
>> --- a/src/gtkutil.c
>> +++ b/src/gtkutil.c
>> @@ -30,6 +30,7 @@ Copyright (C) 2003-2025 Free Software Foundation, Inc.
>> #include "dispextern.h"
>> #include "frame.h"
>> #include "systime.h"
>> +#include "xsettings.h"
>> #ifndef HAVE_PGTK
>> #include "xterm.h"
>> #define xp x
>> @@ -1450,6 +1451,57 @@ xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
>> #endif
>> }
>>
>> +/* Apply dark mode preference to GTK window decorations. */
>> +
>> +void
>> +xg_set_gtk_theme_dark_mode (struct frame *f, bool dark_mode_p)
>> +{
>> +#ifdef HAVE_PGTK
>> + GtkWidget *widget = FRAME_GTK_OUTER_WIDGET (f);
>> + if (widget && GTK_IS_WINDOW (widget))
>> + {
>> + GtkSettings *settings = gtk_widget_get_settings (widget);
>> + if (settings)
>> + {
>> + g_object_set (settings, "gtk-application-prefer-dark-theme",
>> + dark_mode_p ? TRUE : FALSE, NULL);
>> + }
>> + }
>> +#endif
>> +}
> Thanks. I suggest not defining functions that only produce an effect on
> PGTK on other GTK configurations, not least on GTK+ 2.x, where these
> stylistic preferences do not exist at all.
>
>> +/* Update all frames' dark mode based on system setting. */
>> +
>> +void
>> +xg_update_dark_mode_for_all_frames (bool dark_mode_p)
>> +{
>> +#ifdef HAVE_PGTK
>> + struct frame *f;
>> + Lisp_Object tail, frame;
>> +
>> + /* Only update frames if the frame list is initialized */
>> + if (NILP (Vframe_list))
>> + return;
> This test is unnecessary as the frame list will always be initialized by
> the time it is possible for settings callbacks to be invoked.
>
>> + FOR_EACH_FRAME (tail, frame)
>> + {
>> + f = XFRAME (frame);
>> + if (f && FRAME_GTK_WIDGET (f) && FRAME_GTK_OUTER_WIDGET (f))
> These macros are not valid for non-GUI frames, which you must detect
> with `FRAME_PGTK_P (f)'.
>
>> + xg_set_gtk_theme_dark_mode (f, dark_mode_p);
>> + }
>> +#endif
>> +}
>> +
>> +/* Set initial dark mode for a new frame (called during frame creation). */
>> +void
>> +xg_set_initial_dark_mode (struct frame *f)
>> +{
>> +#ifdef HAVE_PGTK
>> + bool dark_mode_p = xg_get_system_dark_mode ();
>> + xg_set_gtk_theme_dark_mode (f, dark_mode_p);
>> +#endif
>> +}
> Ditto. Furthermore, it is redundant to iterate over each active frame
> rather than every display connection's GdkScreen, to which GtkSettings
> objects are specific:
>
> struct pgtk_display_info *dpyinfo;
>
> for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
> {
> GdkScreen *screen
> = gdk_display_get_default_screen (dpyinfo->gdpy);
> GtkSettings *settings
> = gtk_settings_get_for_screen (screen);
>
> [...]
> }
>
>> +extern void xg_set_gtk_theme_dark_mode (struct frame *f, bool dark_mode_p);
>> +extern void xg_update_dark_mode_for_all_frames (bool dark_mode_p);
>> +extern void xg_set_initial_dark_mode (struct frame *f);
> [...]
>
>> +extern bool xg_get_system_dark_mode (void);
>> #endif /* XSETTINGS_H */
> These functions should not be declared when !HAVE_PGTK.
[0003-Automatically-toggle-between-dark-and-light-mode-PGT.patch (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Mon, 27 Oct 2025 01:34:01 GMT)
Full text and
rfc822 format available.
Message #23 received at 79689 <at> debbugs.gnu.org (full text, mbox):
Ahmed Khanzada <me <at> enzu.ru> writes:
> +#ifdef HAVE_PGTK
> +void
> +xg_update_dark_mode_for_all_displays (bool dark_mode_p)
> +{
> + struct pgtk_display_info *dpyinfo;
> + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
> + {
> + GdkScreen *screen
> + = gdk_display_get_default_screen (dpyinfo->gdpy);
> + GtkSettings *settings
> + = gtk_settings_get_for_screen (screen);
> + xg_set_gtk_theme_dark_mode(dark_mode_p, settings);
^
Missing whitespace before parameter list.
> +#ifdef HAVE_PGTK
> +void
> +xg_set_initial_dark_mode (struct frame *f)
> +{
> + bool dark_mode_p = xg_get_system_dark_mode ();
> + xg_update_dark_mode_for_all_displays(dark_mode_p);
^
Likewise.
> + /* Check if we're in dark mode and update all frames */
Missing punctuation after sentence.
Otherwise, you're set to go. Thank you for your interest in GNU Emacs.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Mon, 27 Oct 2025 02:38:01 GMT)
Full text and
rfc822 format available.
Message #26 received at 79689 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gotcha, attached the latest patch. Thanks, this is my first contribution
to the Emacs C code base after a few Lisp ones I've done over the years,
most notably expanding unit test coverage for cl-lib.
On 10/26/25 6:33 PM, Po Lu wrote:
> Ahmed Khanzada <me <at> enzu.ru> writes:
>
>> +#ifdef HAVE_PGTK
>> +void
>> +xg_update_dark_mode_for_all_displays (bool dark_mode_p)
>> +{
>> + struct pgtk_display_info *dpyinfo;
>> + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
>> + {
>> + GdkScreen *screen
>> + = gdk_display_get_default_screen (dpyinfo->gdpy);
>> + GtkSettings *settings
>> + = gtk_settings_get_for_screen (screen);
>> + xg_set_gtk_theme_dark_mode(dark_mode_p, settings);
> ^
> Missing whitespace before parameter list.
>
>> +#ifdef HAVE_PGTK
>> +void
>> +xg_set_initial_dark_mode (struct frame *f)
>> +{
>> + bool dark_mode_p = xg_get_system_dark_mode ();
>> + xg_update_dark_mode_for_all_displays(dark_mode_p);
> ^
>
> Likewise.
>
>> + /* Check if we're in dark mode and update all frames */
> Missing punctuation after sentence.
>
> Otherwise, you're set to go. Thank you for your interest in GNU Emacs.
[0004-PGTK-toggle-dark-mode.patch (text/x-patch, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sat, 01 Nov 2025 09:16:01 GMT)
Full text and
rfc822 format available.
Message #29 received at 79689 <at> debbugs.gnu.org (full text, mbox):
> Date: Sun, 26 Oct 2025 19:37:06 -0700
> Cc: 79689 <at> debbugs.gnu.org
> From: Ahmed Khanzada <me <at> enzu.ru>
>
> Gotcha, attached the latest patch. Thanks, this is my first contribution
> to the Emacs C code base after a few Lisp ones I've done over the years,
> most notably expanding unit test coverage for cl-lib.
Thanks. Po Lu, is this okay to install?
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sun, 02 Nov 2025 00:38:02 GMT)
Full text and
rfc822 format available.
Message #32 received at 79689 <at> debbugs.gnu.org (full text, mbox):
Eli Zaretskii <eliz <at> gnu.org> writes:
> Thanks. Po Lu, is this okay to install?
Yes, if Ahmed has papers.
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79689; Package
emacs.
(Sun, 02 Nov 2025 04:43:02 GMT)
Full text and
rfc822 format available.
Message #35 received at 79689 <at> debbugs.gnu.org (full text, mbox):
Yup, I have signed papers for GNU Emacs on file.
On Sat, Nov 1, 2025, at 5:36 PM, Po Lu wrote:
> Eli Zaretskii <eliz <at> gnu.org> writes:
>
>> Thanks. Po Lu, is this okay to install?
>
> Yes, if Ahmed has papers.
Reply sent
to
Eli Zaretskii <eliz <at> gnu.org>:
You have taken responsibility.
(Sun, 02 Nov 2025 06:04:02 GMT)
Full text and
rfc822 format available.
Notification sent
to
Ahmed Khanzada <me <at> enzu.ru>:
bug acknowledged by developer.
(Sun, 02 Nov 2025 06:04:02 GMT)
Full text and
rfc822 format available.
Message #40 received at 79689-done <at> debbugs.gnu.org (full text, mbox):
> From: Po Lu <luangruo <at> yahoo.com>
> Cc: Ahmed Khanzada <me <at> enzu.ru>, 79689 <at> debbugs.gnu.org
> Date: Sun, 02 Nov 2025 08:36:48 +0800
>
> Eli Zaretskii <eliz <at> gnu.org> writes:
>
> > Thanks. Po Lu, is this okay to install?
>
> Yes, if Ahmed has papers.
Done, and closing the bug.
Thanks.
This bug report was last modified 4 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.