Compare commits

...

11 Commits

Author SHA1 Message Date
Matthias Clasen
b1038c5d19 settings: Add a :theme-change signal
This signal allows applications to intercept and override
what theme gets loaded when the theme settings change.
One possibility is to only load themes from a fixed list
of supported themes. Another is to ignore the user preference
and only load dark themes.
2020-04-13 10:40:32 -04:00
Matthias Clasen
b16b44f1ae inspector: Use theme apis
We can now use gtk_theme_get_available_themes instead
of our own copy of that code.
2020-04-13 10:40:32 -04:00
Matthias Clasen
37c151ce0f Add some theme apis
Add apis to get the list of available themes,
as well as the dark or light variant of a theme.
2020-04-13 10:40:32 -04:00
Matthias Clasen
eb7ad4bbad Introduce a gtk-user-theme-preference setting
This setting will be interpreted as prefers dark/
prefers light/don't care. Since we don't have any
useful metadata for themes, we simply look for
the NAME/NAME-dark naming convention when identifying
light or dark theme variants.
2020-04-13 10:20:36 -04:00
Matthias Clasen
cdec487998 cssprovider: Stop supporting theme variants
We are no longer using variants, so drop the variant
argument from gtk_css_provider_load_named().
2020-04-13 10:20:36 -04:00
Matthias Clasen
80d3c68615 testsuite: Stop loading theme variants 2020-04-13 10:20:35 -04:00
Matthias Clasen
ed4b3f8033 Drop the prefer-dark setting
There is no way to win with this setting, so instead
of trying to add yet more override knobs for application
developers, do away with theme variants altogether.

As a user, just pick your favorite theme, and if it
is dark, so be it.

As an app developer, you can inspect the gtk-theme-name
property and match that against your supported themes.
If that is not good enough for you, you can volunteer
to implement a theme property API that would let themes
declare whether they are dark or light.
2020-04-13 10:20:35 -04:00
Matthias Clasen
451e7a5ad2 themes: Make Adwaita-dark a separate theme
We are moving away from theme variants.
2020-04-13 10:20:35 -04:00
Matthias Clasen
89360b26af window: Stop dealing with prefer-dark
Its 2020.  If you want maching window decorations, use CSD.
2020-04-13 10:20:35 -04:00
Matthias Clasen
d3d4fe14c2 inspector: Stop dealing with prefer-dark
This setting is going away.
2020-04-13 10:20:35 -04:00
Matthias Clasen
040175cd92 widget-factory: Stop dealing with prefer-dark
Instead, just toggle between known light/dark pairs
for the builtin themes.
2020-04-13 10:20:35 -04:00
15 changed files with 386 additions and 316 deletions

View File

@@ -25,23 +25,46 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static char *current_theme;
static void
change_dark_state (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
GtkSettings *settings = gtk_settings_get_default ();
gboolean prefer_dark = g_variant_get_boolean (state);
char *theme;
const char *new_theme = NULL;
g_object_set (G_OBJECT (settings),
"gtk-application-prefer-dark-theme",
g_variant_get_boolean (state),
g_object_get (G_OBJECT (settings),
"gtk-theme-name", &theme,
NULL);
g_simple_action_set_state (action, state);
}
if (prefer_dark)
{
if (strcmp (theme, "Adwaita") == 0)
new_theme = "Adwaita-dark";
else if (strcmp (theme, "HighContrastInverse") == 0)
new_theme = "HighContrast";
}
else
{
if (strcmp (theme, "Adwaita-dark") == 0)
new_theme = "Adwaita";
else if (strcmp (theme, "HighContrast") == 0)
new_theme = "HighContrastInverse";
}
static char *current_theme;
static gboolean current_dark;
if (new_theme)
g_object_set (G_OBJECT (settings),
"gtk-theme-name", new_theme,
NULL);
g_simple_action_set_state (action, state);
g_free (theme);
}
static void
change_theme_state (GSimpleAction *action,
@@ -51,41 +74,34 @@ change_theme_state (GSimpleAction *action,
GtkSettings *settings = gtk_settings_get_default ();
const char *s;
const char *theme;
gboolean prefer_dark = FALSE;
s = g_variant_get_string (state, NULL);
if (strcmp (s, "adwaita") == 0)
{
theme = "Adwaita";
prefer_dark = FALSE;
}
else if (strcmp (s, "adwaita-dark") == 0)
{
theme = "Adwaita";
prefer_dark = TRUE;
theme = "Adwaita-dark";
}
else if (strcmp (s, "highcontrast") == 0)
{
theme = "HighContrast";
prefer_dark = FALSE;
}
else if (strcmp (s, "highcontrast-inverse") == 0)
{
theme = "HighContrastInverse";
prefer_dark = FALSE;
}
else if (strcmp (s, "current") == 0)
{
theme = current_theme;
prefer_dark = current_dark;
}
else
return;
g_object_set (G_OBJECT (settings),
"gtk-theme-name", theme,
"gtk-application-prefer-dark-theme", prefer_dark,
NULL);
g_simple_action_set_state (action, state);
@@ -1739,7 +1755,6 @@ activate (GApplication *app)
g_object_get (gtk_settings_get_default (),
"gtk-theme-name", &current_theme,
"gtk-application-prefer-dark-theme", &current_dark,
NULL);
g_type_ensure (my_text_view_get_type ());

View File

@@ -2304,6 +2304,12 @@ GtkSettingsValue
gtk_settings_get_default
gtk_settings_get_for_display
gtk_settings_reset_property
<SUBSECTION>
gtk_theme_get_dark_variant
gtk_theme_get_light_variant
gtk_theme_get_available_themes
<SUBSECTION Standard>
GtkSettingsClass
GTK_IS_SETTINGS

View File

@@ -33,7 +33,7 @@ def get_files(subdir,extension):
xml += '''
<file>theme/Empty/gtk.css</file>
<file>theme/Adwaita/gtk.css</file>
<file>theme/Adwaita/gtk-dark.css</file>
<file alias='theme/Adwaita-dark/gtk.css'>theme/Adwaita/gtk-dark.css</file>
<file>theme/Adwaita/Adwaita.css</file>
<file>theme/Adwaita/Adwaita-dark.css</file>
'''

View File

@@ -230,6 +230,7 @@
#include <gtk/gtktexttag.h>
#include <gtk/gtktexttagtable.h>
#include <gtk/gtktextview.h>
#include <gtk/gtktheme.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtktooltip.h>
#include <gtk/gtktestutils.h>

View File

@@ -1221,17 +1221,16 @@ _gtk_css_provider_get_theme_dir (GtkCssProvider *provider)
/*
* Look for
* $dir/$subdir/gtk-4.16/gtk-$variant.css
* $dir/$subdir/gtk-4.14/gtk-$variant.css
* $dir/$subdir/gtk-4.16/gtk.css
* $dir/$subdir/gtk-4.14/gtk.css
* ...
* $dir/$subdir/gtk-4.0/gtk-$variant.css
* $dir/$subdir/gtk-4.0/gtk.css
* and return the first found file.
*/
static gchar *
_gtk_css_find_theme_dir (const gchar *dir,
const gchar *subdir,
const gchar *name,
const gchar *variant)
const gchar *name)
{
gchar *file;
gchar *base;
@@ -1239,10 +1238,7 @@ _gtk_css_find_theme_dir (const gchar *dir,
gint i;
gchar *path;
if (variant)
file = g_strconcat ("gtk-", variant, ".css", NULL);
else
file = g_strdup ("gtk.css");
file = g_strdup ("gtk.css");
if (subdir)
base = g_build_filename (dir, subdir, name, NULL);
@@ -1270,9 +1266,8 @@ _gtk_css_find_theme_dir (const gchar *dir,
#undef MINOR
static gchar *
_gtk_css_find_theme (const gchar *name,
const gchar *variant)
char *
_gtk_css_find_theme (const char *name)
{
gchar *path;
const char *const *dirs;
@@ -1280,12 +1275,12 @@ _gtk_css_find_theme (const gchar *name,
char *dir;
/* First look in the user's data directory */
path = _gtk_css_find_theme_dir (g_get_user_data_dir (), "themes", name, variant);
path = _gtk_css_find_theme_dir (g_get_user_data_dir (), "themes", name);
if (path)
return path;
/* Next look in the user's home directory */
path = _gtk_css_find_theme_dir (g_get_home_dir (), ".themes", name, variant);
path = _gtk_css_find_theme_dir (g_get_home_dir (), ".themes", name);
if (path)
return path;
@@ -1293,14 +1288,14 @@ _gtk_css_find_theme (const gchar *name,
dirs = g_get_system_data_dirs ();
for (i = 0; dirs[i]; i++)
{
path = _gtk_css_find_theme_dir (dirs[i], "themes", name, variant);
path = _gtk_css_find_theme_dir (dirs[i], "themes", name);
if (path)
return path;
}
/* Finally, try in the default theme directory */
dir = _gtk_get_theme_dir ();
path = _gtk_css_find_theme_dir (dir, NULL, name, variant);
path = _gtk_css_find_theme_dir (dir, NULL, name);
g_free (dir);
return path;
@@ -1310,8 +1305,6 @@ _gtk_css_find_theme (const gchar *name,
* gtk_css_provider_load_named:
* @provider: a #GtkCssProvider
* @name: A theme name
* @variant: (allow-none): variant to load, for example, "dark", or
* %NULL for the default
*
* Loads a theme from the usual theme paths. The actual process of
* finding the theme might change between releases, but it is
@@ -1320,8 +1313,7 @@ _gtk_css_find_theme (const gchar *name,
**/
void
gtk_css_provider_load_named (GtkCssProvider *provider,
const gchar *name,
const gchar *variant)
const gchar *name)
{
gchar *path;
gchar *resource_path;
@@ -1334,10 +1326,7 @@ gtk_css_provider_load_named (GtkCssProvider *provider,
/* try loading the resource for the theme. This is mostly meant for built-in
* themes.
*/
if (variant)
resource_path = g_strdup_printf ("/org/gtk/libgtk/theme/%s/gtk-%s.css", name, variant);
else
resource_path = g_strdup_printf ("/org/gtk/libgtk/theme/%s/gtk.css", name);
resource_path = g_strdup_printf ("/org/gtk/libgtk/theme/%s/gtk.css", name);
if (g_resources_get_info (resource_path, 0, NULL, NULL, NULL))
{
@@ -1348,7 +1337,7 @@ gtk_css_provider_load_named (GtkCssProvider *provider,
g_free (resource_path);
/* Next try looking for files in the various theme directories. */
path = _gtk_css_find_theme (name, variant);
path = _gtk_css_find_theme (name);
if (path)
{
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (provider);
@@ -1375,17 +1364,8 @@ gtk_css_provider_load_named (GtkCssProvider *provider,
{
/* Things failed! Fall back! Fall back! */
if (variant)
{
/* If there was a variant, try without */
gtk_css_provider_load_named (provider, name, NULL);
}
else
{
/* Worst case, fall back to the default */
g_return_if_fail (!g_str_equal (name, DEFAULT_THEME_NAME)); /* infloop protection */
gtk_css_provider_load_named (provider, DEFAULT_THEME_NAME, NULL);
}
g_return_if_fail (!g_str_equal (name, DEFAULT_THEME_NAME)); /* infloop protection */
gtk_css_provider_load_named (provider, DEFAULT_THEME_NAME);
}
}

View File

@@ -63,8 +63,7 @@ void gtk_css_provider_load_from_resource (GtkCssProvider *css_provid
GDK_AVAILABLE_IN_ALL
void gtk_css_provider_load_named (GtkCssProvider *provider,
const char *name,
const char *variant);
const char *name);
G_END_DECLS

View File

@@ -26,6 +26,8 @@ gchar *_gtk_get_theme_dir (void);
const gchar *_gtk_css_provider_get_theme_dir (GtkCssProvider *provider);
char *_gtk_css_find_theme (const char *theme);
void gtk_css_provider_set_keep_css_sections (void);
G_END_DECLS

View File

@@ -29,6 +29,7 @@
#include "gtkstyleproviderprivate.h"
#include "gtktypebuiltins.h"
#include "gtkversion.h"
#include "gtktheme.h"
#include "gtkwidget.h"
#include "gdk/gdk-private.h"
@@ -122,6 +123,8 @@ struct _GtkSettings
struct _GtkSettingsClass
{
GObjectClass parent_class;
char * (* theme_change) (GtkSettings *settings);
};
struct _GtkSettingsValuePrivate
@@ -136,6 +139,13 @@ struct _GtkSettingsPropertyValue
GtkSettingsSource source;
};
enum {
THEME_CHANGE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
enum {
PROP_0,
PROP_DOUBLE_CLICK_TIME,
@@ -146,6 +156,7 @@ enum {
PROP_SPLIT_CURSOR,
PROP_CURSOR_ASPECT_RATIO,
PROP_THEME_NAME,
PROP_USER_THEME_PREFERENCE,
PROP_ICON_THEME_NAME,
PROP_DND_DRAG_THRESHOLD,
PROP_FONT_NAME,
@@ -170,7 +181,6 @@ enum {
PROP_ENABLE_INPUT_FEEDBACK_SOUNDS,
PROP_ENABLE_EVENT_SOUNDS,
PROP_PRIMARY_BUTTON_WARPS_SLIDER,
PROP_APPLICATION_PREFER_DARK_THEME,
PROP_ENTRY_SELECT_ON_FOCUS,
PROP_ENTRY_PASSWORD_HINT_TIMEOUT,
PROP_LABEL_SELECT_ON_FOCUS,
@@ -223,6 +233,7 @@ static void gtk_settings_load_from_key_file (GtkSettings *setting
static void settings_update_provider (GdkDisplay *display,
GtkCssProvider **old,
GtkCssProvider *new);
static char *gtk_settings_theme_change (GtkSettings *settings);
/* --- variables --- */
static GQuark quark_gtk_settings = 0;
@@ -321,6 +332,8 @@ gtk_settings_class_init (GtkSettingsClass *class)
gobject_class->set_property = gtk_settings_set_property;
gobject_class->notify = gtk_settings_notify;
class->theme_change = gtk_settings_theme_change;
quark_gtk_settings = g_quark_from_static_string ("gtk-settings");
result = settings_install_property_parser (class,
@@ -401,6 +414,14 @@ gtk_settings_class_init (GtkSettingsClass *class)
GTK_PARAM_READWRITE));
g_assert (result == PROP_THEME_NAME);
result = settings_install_property_parser (class,
g_param_spec_int ("gtk-user-theme-preference",
P_("User theme preference"),
P_("User theme preference, 0=light, 1=dark, -1=default"),
-1, 1, -1,
GTK_PARAM_READWRITE));
g_assert (result == PROP_USER_THEME_PREFERENCE);
result = settings_install_property_parser (class,
g_param_spec_string ("gtk-icon-theme-name",
P_("Icon Theme Name"),
@@ -715,29 +736,6 @@ gtk_settings_class_init (GtkSettingsClass *class)
GTK_PARAM_READWRITE));
g_assert (result == PROP_PRIMARY_BUTTON_WARPS_SLIDER);
/**
* GtkSettings:gtk-application-prefer-dark-theme:
*
* Whether the application prefers to use a dark theme. If a GTK theme
* includes a dark variant, it will be used instead of the configured
* theme.
*
* Some applications benefit from minimizing the amount of light pollution that
* interferes with the content. Good candidates for dark themes are photo and
* video editors that make the actual content get all the attention and minimize
* the distraction of the chrome.
*
* Dark themes should not be used for documents, where large spaces are white/light
* and the dark chrome creates too much contrast (web browser, text editor...).
*/
result = settings_install_property_parser (class,
g_param_spec_boolean ("gtk-application-prefer-dark-theme",
P_("Application prefers a dark theme"),
P_("Whether the application prefers to have a dark theme."),
FALSE,
GTK_PARAM_READWRITE));
g_assert (result == PROP_APPLICATION_PREFER_DARK_THEME);
result = settings_install_property_parser (class,
g_param_spec_boolean ("gtk-entry-select-on-focus",
P_("Select on focus"),
@@ -964,6 +962,33 @@ gtk_settings_class_init (GtkSettingsClass *class)
TRUE,
GTK_PARAM_READWRITE));
g_assert (result == PROP_OVERLAY_SCROLLING);
/**
* GtkSettings::theme-change:
* @settings: the #GtkSettings object
*
* The ::theme-change signal is emitted whenever the
* #GtkSettings:gtk-theme-name or #GtkSettings:gtk-user-theme-preference
* settings change. A handler for this signal can inspect the
* values of these properties, and return the name of the theme
* to load.
*
* The default handler will try to find a light or dark variant
* of the theme named by :gtk-theme-name, depending on the value
* of :gtk-user-theme-preference.
*
* Returns: (transfer full): a newly allocated string naming the
* theme to load
*/
signals[THEME_CHANGE] =
g_signal_new (I_("theme-change"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkSettingsClass, theme_change),
g_signal_accumulator_first_wins, NULL,
NULL,
G_TYPE_STRING, 0);
}
static GtkSettings *
@@ -980,6 +1005,7 @@ gtk_settings_provider_iface_init (GtkStyleProviderInterface *iface)
static void
gtk_settings_finalize (GObject *object)
{
GtkSettings *settings = GTK_SETTINGS (object);
guint i;
@@ -1248,7 +1274,7 @@ gtk_settings_notify (GObject *object,
gtk_style_context_reset_widgets (settings->display);
break;
case PROP_THEME_NAME:
case PROP_APPLICATION_PREFER_DARK_THEME:
case PROP_USER_THEME_PREFERENCE:
settings_update_theme (settings);
break;
case PROP_XFT_DPI:
@@ -1638,62 +1664,64 @@ settings_update_provider (GdkDisplay *display,
}
}
static void
get_theme_name (GtkSettings *settings,
gchar **theme_name,
gchar **theme_variant)
{
gboolean prefer_dark;
/* Implement the user theme preference, as well as we can
* without proper theme apis. We treat the builting themes
* as light/dark pairs:
*
* Adwaita/Adwaita-dark
* HighContrast/HighContrastInverse
*
* and we also look for theme pairs of the form
*
* NAME/NAME-dark
*/
*theme_name = NULL;
*theme_variant = NULL;
static char *
gtk_settings_theme_change (GtkSettings *settings)
{
char *theme_name = NULL;
char *theme;
int user_pref;
if (g_getenv ("GTK_THEME"))
*theme_name = g_strdup (g_getenv ("GTK_THEME"));
theme_name = g_strdup (g_getenv ("GTK_THEME"));
if (*theme_name && **theme_name)
{
char *p;
p = strrchr (*theme_name, ':');
if (p) {
*p = '\0';
p++;
*theme_variant = g_strdup (p);
}
return;
}
g_free (*theme_name);
if (theme_name)
return theme_name;
g_object_get (settings,
"gtk-theme-name", theme_name,
"gtk-application-prefer-dark-theme", &prefer_dark,
"gtk-theme-name", &theme_name,
"gtk-user-theme-preference", &user_pref,
NULL);
if (prefer_dark)
*theme_variant = g_strdup ("dark");
switch (user_pref)
{
case 0:
theme = gtk_theme_get_light_variant (theme_name);
g_free (theme_name);
break;
case 1:
theme = gtk_theme_get_dark_variant (theme_name);
g_free (theme_name);
break;
default:
theme = theme_name;
break;
}
if (*theme_name && **theme_name)
return;
g_free (*theme_name);
*theme_name = g_strdup (DEFAULT_THEME_NAME);
return theme;
}
static void
settings_update_theme (GtkSettings *settings)
{
gchar *theme_name;
gchar *theme_variant;
const gchar *theme_dir;
gchar *path;
char *theme_name;
const char *theme_dir;
char *path;
get_theme_name (settings, &theme_name, &theme_variant);
g_signal_emit (settings, signals[THEME_CHANGE], 0, &theme_name);
gtk_css_provider_load_named (settings->theme_provider,
theme_name,
theme_variant);
gtk_css_provider_load_named (settings->theme_provider, theme_name);
/* reload per-theme settings */
theme_dir = _gtk_css_provider_get_theme_dir (settings->theme_provider);
@@ -1706,7 +1734,6 @@ settings_update_theme (GtkSettings *settings)
}
g_free (theme_name);
g_free (theme_variant);
}
const cairo_font_options_t *

181
gtk/gtktheme.c Normal file
View File

@@ -0,0 +1,181 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtktheme.h"
#include "gtkcssproviderprivate.h"
static gboolean
theme_exists (const char *theme)
{
char *path;
path = _gtk_css_find_theme (theme);
if (path)
{
g_free (path);
return TRUE;
}
return FALSE;
}
/**
* gtk_theme_get_dark_variant:
* @theme: a theme name
*
* Returns the name of the dark variant of the
* given theme, if such a variant is available.
* Otherwise, @theme is returned.
*
* Returns: (transfer full): name of the dark variant
* of @theme. Free with g_free()
*/
char *
gtk_theme_get_dark_variant (const char *theme)
{
if (g_str_equal (theme, "HighContrast"))
return g_strdup ("HighContrastInverse");
if (g_str_equal (theme, "Adwaita"))
return g_strdup ("Adwaita-dark");
if (!g_str_has_suffix (theme, "-dark"))
{
char *dark = g_strconcat (theme, "-dark", NULL);
if (theme_exists (dark))
return dark;
g_free (dark);
}
return g_strdup (theme);
}
/**
* gtk_theme_get_light_variant:
* @theme: a theme name
*
* Returns the name of the light variant of the
* given theme, if such a variant is available.
* Otherwise, @theme is returned.
*
* Returns: (transfer full): name of the light variant
* of @theme. Free with g_free()
*/
char *
gtk_theme_get_light_variant (const char *theme)
{
if (g_str_equal (theme, "HighContrastInverse"))
return g_strdup ("HighContrast");
if (g_str_equal (theme, "Adwaita-dark"))
return g_strdup ("Adwaita");
if (g_str_has_suffix (theme, "-dark"))
{
char *light = g_strndup (theme, strlen (theme) - strlen ("-dark"));
if (theme_exists (light))
return light;
g_free (light);
}
return g_strdup (theme);
}
static void
fill_gtk (const gchar *path,
GHashTable *t)
{
const gchar *dir_entry;
GDir *dir = g_dir_open (path, 0, NULL);
if (!dir)
return;
while ((dir_entry = g_dir_read_name (dir)))
{
gchar *filename = g_build_filename (path, dir_entry, "gtk-4.0", "gtk.css", NULL);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) &&
!g_hash_table_contains (t, dir_entry))
g_hash_table_add (t, g_strdup (dir_entry));
g_free (filename);
}
g_dir_close (dir);
}
/**
* gtk_theme_get_available_themes:
*
* Returns the list of available themes.
*
* Returns: (transfer full): an array of theme names
*/
char **
gtk_theme_get_available_themes (void)
{
GHashTable *t;
gchar *path;
gchar **builtin_themes;
guint i;
const gchar * const *dirs;
char **keys;
char **result;
t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
/* Builtin themes */
builtin_themes = g_resources_enumerate_children ("/org/gtk/libgtk/theme", 0, NULL);
for (i = 0; builtin_themes[i] != NULL; i++)
{
if (g_str_has_suffix (builtin_themes[i], "/"))
g_hash_table_add (t, g_strndup (builtin_themes[i], strlen (builtin_themes[i]) - 1));
}
g_strfreev (builtin_themes);
path = _gtk_get_theme_dir ();
fill_gtk (path, t);
g_free (path);
path = g_build_filename (g_get_user_data_dir (), "themes", NULL);
fill_gtk (path, t);
g_free (path);
path = g_build_filename (g_get_home_dir (), ".themes", NULL);
fill_gtk (path, t);
g_free (path);
dirs = g_get_system_data_dirs ();
for (i = 0; dirs[i]; i++)
{
path = g_build_filename (dirs[i], "themes", NULL);
fill_gtk (path, t);
g_free (path);
}
keys = (char **)g_hash_table_get_keys_as_array (t, NULL);
result = g_strdupv (keys);
g_free (keys);
g_hash_table_destroy (t);
return result;
}

38
gtk/gtktheme.h Normal file
View File

@@ -0,0 +1,38 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2020 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_THEME_H__
#define __GTK_THEME_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtktypes.h>
G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
char * gtk_theme_get_dark_variant (const char *theme);
GDK_AVAILABLE_IN_ALL
char * gtk_theme_get_light_variant (const char *theme);
GDK_AVAILABLE_IN_ALL
char **gtk_theme_get_available_themes (void);
G_END_DECLS
#endif /* __GTK_THEME_H__ */

View File

@@ -462,12 +462,6 @@ static void get_shadow_width (GtkWindow *window,
static gboolean gtk_window_activate_menubar (GtkWidget *widget,
GVariant *args,
gpointer unused);
#ifdef GDK_WINDOWING_X11
static void gtk_window_on_theme_variant_changed (GtkSettings *settings,
GParamSpec *pspec,
GtkWindow *window);
#endif
static void gtk_window_set_theme_variant (GtkWindow *window);
static void gtk_window_activate_default_activate (GtkWidget *widget,
const char *action_name,
@@ -1707,12 +1701,6 @@ gtk_window_init (GtkWindow *window)
g_object_ref_sink (window);
priv->has_user_ref_count = TRUE;
#ifdef GDK_WINDOWING_X11
g_signal_connect (gtk_settings_get_for_display (priv->display),
"notify::gtk-application-prefer-dark-theme",
G_CALLBACK (gtk_window_on_theme_variant_changed), window);
#endif
widget_node = gtk_widget_get_css_node (GTK_WIDGET (window));
priv->decoration_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->decoration_node, g_quark_from_static_string ("decoration"));
@@ -4055,12 +4043,6 @@ gtk_window_finalize (GObject *object)
device_removed_cb,
window);
#ifdef GDK_WINDOWING_X11
g_signal_handlers_disconnect_by_func (gtk_settings_get_for_display (priv->display),
gtk_window_on_theme_variant_changed,
window);
#endif
g_free (priv->startup_id);
if (priv->mnemonics_display_timeout_id)
@@ -4331,8 +4313,6 @@ gtk_window_map (GtkWidget *widget)
if (priv->minimize_initially)
gdk_toplevel_minimize (GDK_TOPLEVEL (priv->surface));
gtk_window_set_theme_variant (window);
/* No longer use the default settings */
priv->need_default_size = FALSE;
@@ -7081,14 +7061,6 @@ gtk_window_set_display (GtkWindow *window,
if (priv->transient_parent && gtk_widget_get_display (GTK_WIDGET (priv->transient_parent)) != display)
gtk_window_set_transient_for (window, NULL);
#ifdef GDK_WINDOWING_X11
g_signal_handlers_disconnect_by_func (gtk_settings_get_for_display (priv->display),
gtk_window_on_theme_variant_changed, window);
g_signal_connect (gtk_settings_get_for_display (display),
"notify::gtk-application-prefer-dark-theme",
G_CALLBACK (gtk_window_on_theme_variant_changed), window);
#endif
gtk_widget_unroot (widget);
priv->display = display;
@@ -7102,33 +7074,6 @@ gtk_window_set_display (GtkWindow *window,
check_scale_changed (window);
}
static void
gtk_window_set_theme_variant (GtkWindow *window)
{
#ifdef GDK_WINDOWING_X11
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
gboolean dark_theme_requested;
g_object_get (gtk_settings_get_for_display (priv->display),
"gtk-application-prefer-dark-theme", &dark_theme_requested,
NULL);
if (GDK_IS_X11_SURFACE (priv->surface))
gdk_x11_surface_set_theme_variant (priv->surface,
dark_theme_requested ? "dark" : NULL);
#endif
}
#ifdef GDK_WINDOWING_X11
static void
gtk_window_on_theme_variant_changed (GtkSettings *settings,
GParamSpec *pspec,
GtkWindow *window)
{
gtk_window_set_theme_variant (window);
}
#endif
/**
* gtk_window_is_active:
* @window: a #GtkWindow

View File

@@ -42,6 +42,7 @@
#include "gskrendererprivate.h"
#include "gtknative.h"
#include "gtkbinlayout.h"
#include "gtktheme.h"
#include "fallback-c89.c"
@@ -62,7 +63,6 @@ struct _GtkInspectorVisualPrivate
GtkWidget *box;
GtkWidget *visual_box;
GtkWidget *theme_combo;
GtkWidget *dark_switch;
GtkWidget *icon_combo;
GtkWidget *cursor_combo;
GtkWidget *cursor_size_spin;
@@ -474,30 +474,6 @@ focus_activate (GtkSwitch *sw,
redraw_everything ();
}
static void
fill_gtk (const gchar *path,
GHashTable *t)
{
const gchar *dir_entry;
GDir *dir = g_dir_open (path, 0, NULL);
if (!dir)
return;
while ((dir_entry = g_dir_read_name (dir)))
{
gchar *filename = g_build_filename (path, dir_entry, "gtk-4.0", "gtk.css", NULL);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) &&
!g_hash_table_contains (t, dir_entry))
g_hash_table_add (t, g_strdup (dir_entry));
g_free (filename);
}
g_dir_close (dir);
}
static gchar*
get_data_path (const gchar *subdir)
{
@@ -515,57 +491,14 @@ get_data_path (const gchar *subdir)
static void
init_theme (GtkInspectorVisual *vis)
{
GHashTable *t;
GHashTableIter iter;
gchar *theme, *path;
gchar **builtin_themes;
GList *list, *l;
guint i;
const gchar * const *dirs;
char **themes;
int i;
t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
/* Builtin themes */
builtin_themes = g_resources_enumerate_children ("/org/gtk/libgtk/theme", 0, NULL);
for (i = 0; builtin_themes[i] != NULL; i++)
{
if (g_str_has_suffix (builtin_themes[i], "/"))
g_hash_table_add (t, g_strndup (builtin_themes[i], strlen (builtin_themes[i]) - 1));
}
g_strfreev (builtin_themes);
themes = gtk_theme_get_available_themes ();
for (i = 0; themes[i]; i++)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (vis->priv->theme_combo), themes[i], themes[i]);
path = _gtk_get_theme_dir ();
fill_gtk (path, t);
g_free (path);
path = g_build_filename (g_get_user_data_dir (), "themes", NULL);
fill_gtk (path, t);
g_free (path);
path = g_build_filename (g_get_home_dir (), ".themes", NULL);
fill_gtk (path, t);
g_free (path);
dirs = g_get_system_data_dirs ();
for (i = 0; dirs[i]; i++)
{
path = g_build_filename (dirs[i], "themes", NULL);
fill_gtk (path, t);
g_free (path);
}
list = NULL;
g_hash_table_iter_init (&iter, t);
while (g_hash_table_iter_next (&iter, (gpointer *)&theme, NULL))
list = g_list_insert_sorted (list, theme, (GCompareFunc)strcmp);
for (l = list; l; l = l->next)
{
theme = l->data;
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (vis->priv->theme_combo), theme, theme);
}
g_list_free (list);
g_hash_table_destroy (t);
g_strfreev (themes);
g_object_bind_property (gtk_settings_get_for_display (vis->priv->display),
"gtk-theme-name",
@@ -583,25 +516,6 @@ init_theme (GtkInspectorVisual *vis)
}
}
static void
init_dark (GtkInspectorVisual *vis)
{
g_object_bind_property (gtk_settings_get_for_display (vis->priv->display),
"gtk-application-prefer-dark-theme",
vis->priv->dark_switch, "active",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
if (g_getenv ("GTK_THEME") != NULL)
{
GtkWidget *row;
/* theme is hardcoded, nothing we can do */
gtk_widget_set_sensitive (vis->priv->dark_switch, FALSE);
row = gtk_widget_get_ancestor (vis->priv->theme_combo, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_set_tooltip_text (row, _("Theme is hardcoded by GTK_THEME"));
}
}
static void
fill_icons (const gchar *path,
GHashTable *t)
@@ -959,12 +873,7 @@ row_activated (GtkListBox *box,
GtkListBoxRow *row,
GtkInspectorVisual *vis)
{
if (gtk_widget_is_ancestor (vis->priv->dark_switch, GTK_WIDGET (row)))
{
GtkSwitch *sw = GTK_SWITCH (vis->priv->dark_switch);
gtk_switch_set_active (sw, !gtk_switch_get_active (sw));
}
else if (gtk_widget_is_ancestor (vis->priv->animation_switch, GTK_WIDGET (row)))
if (gtk_widget_is_ancestor (vis->priv->animation_switch, GTK_WIDGET (row)))
{
GtkSwitch *sw = GTK_SWITCH (vis->priv->animation_switch);
gtk_switch_set_active (sw, !gtk_switch_get_active (sw));
@@ -1125,7 +1034,6 @@ gtk_inspector_visual_class_init (GtkInspectorVisualClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, box);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, direction_combo);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, theme_combo);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, dark_switch);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, cursor_combo);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, cursor_size_spin);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, cursor_size_adjustment);
@@ -1172,7 +1080,6 @@ gtk_inspector_visual_set_display (GtkInspectorVisual *vis,
init_direction (vis);
init_theme (vis);
init_dark (vis);
init_icons (vis);
init_cursors (vis);
init_cursor_size (vis);

View File

@@ -74,34 +74,6 @@
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="spacing">40</property>
<child>
<object class="GtkLabel" id="dark_label">
<property name="label" translatable="yes">Dark Variant</property>
<property name="halign">start</property>
<property name="valign">baseline</property>
<property name="xalign">0.0</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="dark_switch">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
@@ -691,7 +663,6 @@
<object class="GtkSizeGroup">
<widgets>
<widget name="theme_label"/>
<widget name="dark_label"/>
<widget name="icon_label"/>
<widget name="cursor_label"/>
<widget name="cursor_size_label"/>

View File

@@ -370,6 +370,7 @@ gtk_public_sources = files([
'gtktexttypes.c',
'gtktextutil.c',
'gtktextview.c',
'gtktheme.c',
'gtktogglebutton.c',
'gtktooltip.c',
'gtktooltipwindow.c',
@@ -602,6 +603,7 @@ gtk_public_headers = files([
'gtktexttag.h',
'gtktexttagtable.h',
'gtktextview.h',
'gtktheme.h',
'gtktogglebutton.h',
'gtktooltip.h',
'gtktreednd.h',

View File

@@ -5,7 +5,6 @@ typedef struct _Theme Theme;
struct _Theme
{
const char *name;
const char *variant;
};
static void
@@ -34,7 +33,7 @@ test_theme (gconstpointer data)
provider = gtk_css_provider_new ();
g_signal_connect (provider, "parsing-error",
G_CALLBACK (theme_parsing_error), NULL);
gtk_css_provider_load_named (provider, theme->name, theme->variant);
gtk_css_provider_load_named (provider, theme->name);
g_object_unref (provider);
}
@@ -42,10 +41,10 @@ int
main (int argc, char *argv[])
{
const Theme themes[] = {
{ "Adwaita", NULL },
{ "Adwaita", "dark" },
{ "HighContrast", NULL },
{ "HighContrast", "dark" }
{ "Adwaita" },
{ "Adwaita-dark" },
{ "HighContrast" },
{ "HighContrastInverse" }
};
guint i;
@@ -56,10 +55,7 @@ main (int argc, char *argv[])
{
char *testname;
if (themes[i].variant == NULL)
testname = g_strdup_printf ("/theme-validate/%s", themes[i].name);
else
testname = g_strdup_printf ("/theme-validate/%s-%s", themes[i].name, themes[i].variant);
testname = g_strdup_printf ("/theme-validate/%s", themes[i].name);
g_test_add_data_func (testname, &themes[i], test_theme);