/* vim: colorcolumn=80 ts=4 sw=4
 */
/* -*- mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* configuration.c - configuration loading/saving via GSettings

   Copyright (C) 1997 - 2004 Free Software Foundation

   Copyright © 2005-2020 Various individual contributors, including
   but not limited to: Jonathon Jongsma, Kalev Lember, who continued
   to maintain the source code under the licensing terms described
   herein and below.

   Copyright © 2021 Logan Rathbone <poprocks@gmail.com>

   GHex 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.

   GHex 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 GHex; see the file COPYING.
   If not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

   Author: Jaka Mocnik <jaka@gnu.org>
*/

#include <config.h>

#include "configuration.h"

GSettings *settings;
/* Global CSS provider for our HexWidget widgets */
GtkCssProvider *provider;

int def_group_type;
char *def_font_name;
char *header_font_name;
char *data_font_name;
guint shaded_box_size;
gboolean show_offsets_column;
int def_dark_mode;
/* Will default to false here. We can't set it until we get a 'screen', so
 * we'll save calling get_sys_default_is_dark() until GHex launches. */
gboolean sys_default_is_dark;

static void
offsets_column_changed_cb (GSettings   *settings,
                           const gchar *key,
                           gpointer     user_data)
{
    gboolean show_off = g_settings_get_boolean (settings, key);

    show_offsets_column = show_off;
}

static void
group_changed_cb (GSettings   *settings,
                  const gchar *key,
                  gpointer     user_data)
{
    def_group_type = g_settings_get_enum (settings, key);
}

static void
dark_mode_changed_cb (GSettings   *settings,
                  const gchar *key,
                  gpointer     user_data)
{
    def_dark_mode = g_settings_get_enum (settings, key);
}


/* NOTE: for GTK 4.0 backwards compatibility, we manually define these
 * here. If we wish to add an additional dependency on
 * gsettings-desktop-schemas >= 42, this can be eliminated.
 */
enum system_color_scheme {
	SYSTEM_DEFAULT,
	SYSTEM_PREFER_DARK,
	SYSTEM_PREFER_LIGHT,
};

static gboolean
try_dark_from_gsettings (void)
{
	int color_scheme;
	GSettingsSchemaSource *source;
	GSettingsSchema *schema;
	char *schema_id = NULL;

	source = g_settings_schema_source_get_default ();
	schema = g_settings_schema_source_lookup (source, "org.freedesktop.appearance", TRUE);

	if (schema && g_settings_schema_has_key (schema, "color-scheme"))
	{
		schema_id = "org.freedesktop.appearance";
	}
	else
	{
		g_clear_pointer (&schema, g_settings_schema_unref);
		schema = g_settings_schema_source_lookup (source, "org.gnome.desktop.interface", TRUE);
		if (schema && g_settings_schema_has_key (schema, "color-scheme"))
		{
			schema_id = "org.gnome.desktop.interface";
		}
		g_clear_pointer (&schema, g_settings_schema_unref);
	}

	if (schema_id)
	{
		GSettings *set = g_settings_new (schema_id);
		color_scheme = g_settings_get_enum (set, "color-scheme");
		if (color_scheme == SYSTEM_PREFER_DARK)
			sys_default_is_dark = TRUE;
		g_object_unref (set);

		return TRUE;
	}
	return FALSE;
}

static gboolean
try_dark_from_portal (void)
{
	int color_scheme;
	char *color_scheme_str = NULL;
	GDBusProxy *settings_portal = NULL;
	GVariant *gvar = NULL, *gvar2 = NULL;
	gboolean retval = FALSE;

	settings_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,
			NULL);

	if (! settings_portal)
		goto out;

	gvar = g_dbus_proxy_call_sync (settings_portal,
			"Read",
			g_variant_new ("(ss)", "org.freedesktop.appearance", "color-scheme"),
			G_DBUS_CALL_FLAGS_NONE,
			G_MAXINT,
			NULL,
			NULL);

	if (gvar)
	{
		g_variant_get (gvar, "(v)", &gvar2);
		g_variant_get (g_variant_get_variant (gvar2), "u", &color_scheme);
		retval = TRUE;
		goto out;
	}

	gvar = g_dbus_proxy_call_sync (settings_portal,
			"Read",
			g_variant_new ("(ss)", "org.gnome.desktop.interface", "color-scheme"),
			G_DBUS_CALL_FLAGS_NONE,
			G_MAXINT,
			NULL,
			NULL);

	if (! gvar)
		goto out;

	g_variant_get (gvar, "(v)", &gvar2);
	g_variant_get (g_variant_get_variant (gvar2), "s", &color_scheme_str);

	if (color_scheme_str)
	{
		retval = TRUE;
		if (g_strcmp0 (color_scheme_str, "prefer-dark") == 0)
			color_scheme = SYSTEM_PREFER_DARK;
	}

out:
	if (color_scheme == SYSTEM_PREFER_DARK)
		sys_default_is_dark = TRUE;

	g_clear_object (&settings_portal);
	g_clear_pointer (&gvar, g_variant_unref);
	g_clear_pointer (&gvar2, g_variant_unref);

	return retval;
}

void
get_sys_default_is_dark (void)
{
	GtkSettings *gtk_settings;
	gboolean got_dark_pref;

	got_dark_pref = try_dark_from_portal ();
	if (got_dark_pref)
		return;

	got_dark_pref = try_dark_from_gsettings ();
	if (got_dark_pref)
		return;

	/* If all else fails, try to fetch from GtkSettings. */
	gtk_settings = gtk_settings_get_default ();
	g_object_get (gtk_settings,
			"gtk-application-prefer-dark-theme", &sys_default_is_dark,
			NULL);
}

static void
box_size_changed_cb (GSettings   *settings,
                     const gchar *key,
                     gpointer     user_data)
{
    g_settings_get (settings, key, "u", &shaded_box_size);
}

static void
font_changed_cb (GSettings   *settings,
                 const gchar *key,
                 gpointer     user_data)
{
    const gchar *font_name = g_settings_get_string (settings, key);

    g_return_if_fail (font_name != NULL);

	if (def_font_name)
		g_free (def_font_name);

	def_font_name = g_strdup (font_name);
}

static void
data_font_changed_cb (GSettings   *settings,
                      const gchar *key,
                      gpointer     user_data)
{
    if (data_font_name)
        g_free (data_font_name);
    data_font_name = g_strdup (g_settings_get_string (settings, key));
}

static void
header_font_changed_cb (GSettings   *settings,
                        const gchar *key,
                        gpointer     user_data)
{
    if (header_font_name)
        g_free (header_font_name);
    header_font_name = g_strdup (g_settings_get_string (settings, key));
}

void ghex_init_configuration ()
{
	/* GSettings */

    settings = g_settings_new (APP_ID);
    g_return_if_fail (settings);

    g_signal_connect (settings, "changed::" GHEX_PREF_OFFSETS_COLUMN,
                      G_CALLBACK (offsets_column_changed_cb), NULL);
    offsets_column_changed_cb (settings, GHEX_PREF_OFFSETS_COLUMN, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_GROUP,
                      G_CALLBACK (group_changed_cb), NULL);
    group_changed_cb (settings, GHEX_PREF_GROUP, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_DARK_MODE,
                      G_CALLBACK (dark_mode_changed_cb), NULL);
    dark_mode_changed_cb (settings, GHEX_PREF_DARK_MODE, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_BOX_SIZE,
                      G_CALLBACK (box_size_changed_cb), NULL);
    box_size_changed_cb (settings, GHEX_PREF_BOX_SIZE, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_FONT,
                      G_CALLBACK (font_changed_cb), NULL);
    font_changed_cb (settings, GHEX_PREF_FONT, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_DATA_FONT,
                      G_CALLBACK (data_font_changed_cb), NULL);

    data_font_changed_cb (settings, GHEX_PREF_DATA_FONT, NULL);

    g_signal_connect (settings, "changed::" GHEX_PREF_HEADER_FONT,
                      G_CALLBACK (header_font_changed_cb), NULL);
    header_font_changed_cb (settings, GHEX_PREF_HEADER_FONT, NULL);

	/* Global CSS provider */

	provider = gtk_css_provider_new ();
}
