mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-13 23:32:55 +00:00
GTK3: Support freedesktop color-scheme
On desktops which support the org.freedesktop.appearance settings portal, the application will switch automatically between light and dark themes.
This commit is contained in:
parent
80d1946efd
commit
bcc06d8d33
290
BasiliskII/src/Unix/color_scheme.cpp
Normal file
290
BasiliskII/src/Unix/color_scheme.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
/* color_scheme.cpp - Change application theme based on D-Bus
|
||||
*
|
||||
* Copyright (C) 2022-2024 Rob Hall
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "color_scheme.h"
|
||||
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
|
||||
#define APP_DARK APP_PREFERS_DARK /* 1 */
|
||||
#define APP_FORCE APP_FORCES_LIGHT /* 2 */
|
||||
#define DBUS_TIMEOUT 1000 /* Timeout for D-Bus to respond in ms */
|
||||
|
||||
#if GLIB_CHECK_VERSION(2, 72, 0)
|
||||
#define SETTING_CHANGED_SIGNAL "g-signal::SettingChanged"
|
||||
#else
|
||||
#define SETTING_CHANGED_SIGNAL "g-signal"
|
||||
#endif
|
||||
|
||||
static AppColorScheme app_scheme = APP_FORCES_LIGHT;
|
||||
static GDBusProxy *desktop_portal;
|
||||
static GtkSettings *settings;
|
||||
static gboolean init_done = FALSE;
|
||||
|
||||
static void
|
||||
set_gtk_theme (gboolean dark)
|
||||
{
|
||||
g_object_set(settings, "gtk-application-prefer-dark-theme", dark, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the currently selected app colour scheme.
|
||||
*/
|
||||
AppColorScheme
|
||||
color_scheme_get_app_scheme (void)
|
||||
{
|
||||
return app_scheme;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE if the app is currently using the dark theme.
|
||||
*/
|
||||
gboolean
|
||||
color_scheme_is_dark_theme (void)
|
||||
{
|
||||
gboolean is_dark;
|
||||
|
||||
g_object_get (settings, "gtk-application-prefer-dark-theme", &is_dark, NULL);
|
||||
return is_dark;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switches the color state of the app, no matter which color
|
||||
* is currently in use. Afterwards, the app color scheme is
|
||||
* changed to APP_FORCES_LIGHT or APP_FORCES_DARK, so changes
|
||||
* to the desktop color scheme no longer have any effect.
|
||||
*/
|
||||
gboolean
|
||||
color_scheme_toggle (void)
|
||||
{
|
||||
gboolean set_dark = !color_scheme_is_dark_theme();
|
||||
g_object_set(settings, "gtk-application-prefer-dark-theme",
|
||||
set_dark, NULL);
|
||||
|
||||
/* Change app_scheme to APP_FORCES_[DARK|LIGHT] */
|
||||
app_scheme = (AppColorScheme) (set_dark | APP_FORCE);
|
||||
|
||||
return set_dark;
|
||||
}
|
||||
|
||||
static void
|
||||
setting_changed (GDBusProxy *proxy, char *sender_name, char *signal_name,
|
||||
GVariant *parameters, gpointer user_data)
|
||||
{
|
||||
const char *namespace_;
|
||||
const char *key;
|
||||
g_autoptr (GVariant) var = NULL;
|
||||
guint32 portal_value;
|
||||
gboolean set_dark;
|
||||
|
||||
if (g_strcmp0(signal_name, "SettingChanged"))
|
||||
return;
|
||||
|
||||
g_variant_get(parameters, "(&s&sv)", &namespace_, &key, &var);
|
||||
|
||||
if (!g_strcmp0(namespace_, "org.freedesktop.appearance") &&
|
||||
!g_strcmp0(key, "color-scheme"))
|
||||
{
|
||||
g_variant_get(var, "u", &portal_value);
|
||||
set_dark = (portal_value == DESKTOP_PREFERS_DARK) ? TRUE : FALSE;
|
||||
if (!(app_scheme & APP_FORCE))
|
||||
set_gtk_theme(set_dark);
|
||||
}
|
||||
}
|
||||
|
||||
static GDBusProxy *
|
||||
portal_init (void)
|
||||
{
|
||||
GDBusProxy *portal;
|
||||
GError *error = NULL;
|
||||
|
||||
portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE, NULL,
|
||||
"org.freedesktop.portal.Desktop",
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.Settings",
|
||||
NULL, &error);
|
||||
if (!portal)
|
||||
g_debug ("Could not access portal: %s", error->message);
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
static void
|
||||
set_theme (void)
|
||||
{
|
||||
DesktopColorScheme desktop_scheme;
|
||||
gboolean set_dark;
|
||||
|
||||
desktop_scheme = color_scheme_get_desktop_scheme();
|
||||
if ((app_scheme & APP_FORCE) || desktop_scheme == DESKTOP_NO_PREFERENCE)
|
||||
set_dark = (app_scheme & APP_DARK);
|
||||
else
|
||||
set_dark = (desktop_scheme == DESKTOP_PREFERS_DARK);
|
||||
|
||||
set_gtk_theme(set_dark);
|
||||
}
|
||||
|
||||
static void
|
||||
init_color_scheme_cb (GObject *object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
GDBusProxy *portal;
|
||||
GError *error = NULL;
|
||||
|
||||
portal = g_dbus_proxy_new_for_bus_finish(res, &error);
|
||||
|
||||
if (portal)
|
||||
{
|
||||
g_signal_connect(portal, SETTING_CHANGED_SIGNAL,
|
||||
G_CALLBACK(setting_changed), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug("Could not access portal: %s", error->message);
|
||||
}
|
||||
init_done = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
init_color_scheme_async (void)
|
||||
{
|
||||
static size_t init = 0;
|
||||
|
||||
if (g_once_init_enter(&init))
|
||||
{
|
||||
settings = gtk_settings_get_default();
|
||||
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE, NULL,
|
||||
"org.freedesktop.portal.Desktop",
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.Settings",
|
||||
NULL,
|
||||
(GAsyncReadyCallback)init_color_scheme_cb,
|
||||
NULL);
|
||||
g_once_init_leave(&init, 1);
|
||||
}
|
||||
set_theme();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
init_color_scheme (void)
|
||||
{
|
||||
static GMutex init_mutex;
|
||||
|
||||
g_mutex_lock(&init_mutex);
|
||||
{
|
||||
if (!init_done)
|
||||
{
|
||||
settings = gtk_settings_get_default();
|
||||
desktop_portal = portal_init();
|
||||
if (desktop_portal)
|
||||
{
|
||||
g_signal_connect(desktop_portal, SETTING_CHANGED_SIGNAL,
|
||||
G_CALLBACK(setting_changed), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
init_done = TRUE;
|
||||
g_mutex_unlock(&init_mutex);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the current desktop color scheme, given by
|
||||
* the org.freedesktop.portal.Settings portal. If the portal
|
||||
* is not available, DESKTOP_NO_PREFERENCE is returned.
|
||||
*/
|
||||
DesktopColorScheme
|
||||
color_scheme_get_desktop_scheme (void)
|
||||
{
|
||||
g_autoptr (GVariant) outer = NULL;
|
||||
g_autoptr (GVariant) inner = NULL;
|
||||
g_autoptr (GVariant) result = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
DesktopColorScheme scheme;
|
||||
|
||||
if (!init_done && !init_color_scheme())
|
||||
return DESKTOP_NO_PREFERENCE;
|
||||
|
||||
if (!desktop_portal)
|
||||
return DESKTOP_NO_PREFERENCE;
|
||||
|
||||
GVariant *call = g_variant_new("(ss)", "org.freedesktop.appearance",
|
||||
"color-scheme");
|
||||
result = g_dbus_proxy_call_sync(desktop_portal, "Read", call,
|
||||
G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT,
|
||||
NULL, &error);
|
||||
if (!result)
|
||||
{
|
||||
g_debug("%s", error->message);
|
||||
return DESKTOP_NO_PREFERENCE;
|
||||
}
|
||||
|
||||
g_variant_get(result, "(v)", &outer);
|
||||
g_variant_get(outer, "v", &inner);
|
||||
scheme = (DesktopColorScheme) g_variant_get_uint32(inner);
|
||||
|
||||
if (scheme > DESKTOP_PREFERS_LIGHT)
|
||||
scheme = DESKTOP_NO_PREFERENCE;
|
||||
return scheme;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the color scheme to one of the four options.
|
||||
* Can be called once GTK has been initialised.
|
||||
* Returns FALSE if the color scheme could not be set.
|
||||
* If the return value is not needed, use color_scheme_set_async instead.
|
||||
*/
|
||||
gboolean
|
||||
color_scheme_set (AppColorScheme scheme)
|
||||
{
|
||||
gboolean set_dark;
|
||||
DesktopColorScheme desktop_scheme;
|
||||
|
||||
if (!init_done && !init_color_scheme())
|
||||
return FALSE;
|
||||
|
||||
app_scheme = scheme;
|
||||
desktop_scheme = color_scheme_get_desktop_scheme();
|
||||
|
||||
if ((app_scheme & APP_FORCE) || desktop_scheme == DESKTOP_NO_PREFERENCE)
|
||||
set_dark = (app_scheme & APP_DARK);
|
||||
else
|
||||
set_dark = (desktop_scheme == DESKTOP_PREFERS_DARK);
|
||||
|
||||
set_gtk_theme(set_dark);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the color scheme to one of the four options.
|
||||
* Can be called once GTK has been initialised.
|
||||
* Runs asynchronously, so preferred over color_scheme_set.
|
||||
*/
|
||||
void
|
||||
color_scheme_set_async (AppColorScheme scheme)
|
||||
{
|
||||
app_scheme = scheme;
|
||||
if (init_done)
|
||||
set_theme();
|
||||
else
|
||||
init_color_scheme_async();
|
||||
}
|
||||
|
||||
#endif // GTK_CHECK_VERSION
|
@ -503,7 +503,7 @@ fi
|
||||
if [[ "x$WANT_GTK" != "xno" -a "x$WANT_STANDALONE_GUI" = "xno" ]]; then
|
||||
AC_DEFINE(ENABLE_GTK, 1, [Define if using GTK.])
|
||||
if [[ "$WANT_GTK" = "GTK3" ]]; then
|
||||
UISRCS="prefs_editor_gtk3.cpp g_resource.cpp"
|
||||
UISRCS="prefs_editor_gtk3.cpp g_resource.cpp color_scheme.cpp"
|
||||
else
|
||||
UISRCS="prefs_editor_gtk.cpp"
|
||||
fi
|
||||
|
@ -73,6 +73,10 @@ struct sigstate {
|
||||
# if GTK_CHECK_VERSION(3, 14, 0)
|
||||
# define ENABLE_GTK3
|
||||
# endif
|
||||
# if GTK_CHECK_VERSION(3, 22, 0)
|
||||
# define ENABLE_GTK_3_22
|
||||
# include "color_scheme.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_XF86_DGA
|
||||
@ -423,6 +427,9 @@ GtkWindow *win;
|
||||
|
||||
static void gui_startup (void)
|
||||
{
|
||||
#ifdef ENABLE_GTK_3_22
|
||||
color_scheme_set(APP_PREFERS_LIGHT);
|
||||
#endif
|
||||
if (!PrefsEditor())
|
||||
QuitEmulator();
|
||||
}
|
||||
|
58
BasiliskII/src/include/color_scheme.h
Normal file
58
BasiliskII/src/include/color_scheme.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* color_scheme.h - Change application theme based on D-Bus
|
||||
*
|
||||
* Copyright (C) 2022-2024 Rob Hall
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* An enum representing the color state requested by
|
||||
* the application. Before the color-scheme library is
|
||||
* set up, the application is effectively in the
|
||||
* APP_FORCES_LIGHT state.
|
||||
*/
|
||||
typedef enum {
|
||||
APP_PREFERS_LIGHT,
|
||||
APP_PREFERS_DARK,
|
||||
APP_FORCES_LIGHT,
|
||||
APP_FORCES_DARK
|
||||
} AppColorScheme;
|
||||
|
||||
/*
|
||||
* An enum representing the color state given by the
|
||||
* desktop portal. If the portal is not available, it
|
||||
* defaults to DESKTOP_NO_PREFERENCE.
|
||||
*/
|
||||
typedef enum {
|
||||
DESKTOP_NO_PREFERENCE,
|
||||
DESKTOP_PREFERS_DARK,
|
||||
DESKTOP_PREFERS_LIGHT
|
||||
} DesktopColorScheme;
|
||||
|
||||
gboolean color_scheme_set (AppColorScheme scheme);
|
||||
void color_scheme_set_async (AppColorScheme scheme);
|
||||
gboolean color_scheme_is_dark_theme (void);
|
||||
gboolean color_scheme_toggle (void);
|
||||
AppColorScheme color_scheme_get_app_scheme (void);
|
||||
DesktopColorScheme color_scheme_get_desktop_scheme (void);
|
||||
|
||||
G_END_DECLS
|
@ -58,7 +58,7 @@ links:
|
||||
include/extfs.h include/extfs_defs.h include/pict.h \
|
||||
include/prefs.h include/scsi.h include/serial.h include/prefs_editor.h \
|
||||
include/serial_defs.h include/sony.h include/sys.h \
|
||||
include/timer.h include/xpram.h \
|
||||
include/timer.h include/xpram.h include/color_scheme.h \
|
||||
BeOS/audio_beos.cpp BeOS/extfs_beos.cpp BeOS/scsi_beos.cpp \
|
||||
BeOS/serial_beos.cpp BeOS/sys_beos.cpp BeOS/timer_beos.cpp \
|
||||
BeOS/xpram_beos.cpp BeOS/SheepDriver BeOS/SheepNet \
|
||||
@ -66,7 +66,7 @@ links:
|
||||
CrossPlatform/video_vosf.h CrossPlatform/video_blit.h CrossPlatform/video_blit.cpp \
|
||||
Unix/audio_oss_esd.cpp \
|
||||
Unix/vhd_unix.cpp \
|
||||
Unix/extfs_unix.cpp Unix/serial_unix.cpp \
|
||||
Unix/extfs_unix.cpp Unix/serial_unix.cpp Unix/color_scheme.cpp \
|
||||
Unix/sshpty.h Unix/sshpty.c Unix/strlcpy.h Unix/strlcpy.c \
|
||||
Unix/sys_unix.cpp Unix/timer_unix.cpp Unix/xpram_unix.cpp Unix/prefs_unix.cpp \
|
||||
Unix/semaphore.h Unix/posix_sem.cpp Unix/config.sub Unix/config.guess Unix/m4 \
|
||||
|
1
SheepShaver/src/Unix/color_scheme.cpp
Symbolic link
1
SheepShaver/src/Unix/color_scheme.cpp
Symbolic link
@ -0,0 +1 @@
|
||||
../../../BasiliskII/src/Unix/color_scheme.cpp
|
@ -380,7 +380,7 @@ fi
|
||||
if [[ "x$WANT_GTK" != "xno" -a "x$WANT_STANDALONE_GUI" = "xno" ]]; then
|
||||
AC_DEFINE(ENABLE_GTK, 1, [Define if using GTK.])
|
||||
if [[ "$WANT_GTK" = "GTK3" ]]; then
|
||||
UISRCS="prefs_editor_gtk3.cpp g_resource.cpp"
|
||||
UISRCS="prefs_editor_gtk3.cpp g_resource.cpp color_scheme.cpp"
|
||||
else
|
||||
UISRCS="prefs_editor_gtk.cpp"
|
||||
fi
|
||||
|
@ -147,6 +147,10 @@
|
||||
#if GTK_CHECK_VERSION(3, 14, 0)
|
||||
#define ENABLE_GTK3
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
#define ENABLE_GTK_3_22
|
||||
#include "color_scheme.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_XF86_DGA
|
||||
@ -762,6 +766,9 @@ GtkWindow *win;
|
||||
|
||||
static void gui_startup (void)
|
||||
{
|
||||
#ifdef ENABLE_GTK_3_22
|
||||
color_scheme_set(APP_PREFERS_LIGHT);
|
||||
#endif
|
||||
if (use_gui && !PrefsEditor())
|
||||
QuitEmulator();
|
||||
}
|
||||
|
1
SheepShaver/src/include/color_scheme.h
Symbolic link
1
SheepShaver/src/include/color_scheme.h
Symbolic link
@ -0,0 +1 @@
|
||||
../../../BasiliskII/src/include/color_scheme.h
|
Loading…
x
Reference in New Issue
Block a user