From a0337d0be899800e3b127beede230a8d1624f9fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 29 May 2014 18:49:57 +0200
Subject: [PATCH 1/4] xsettings: Set Gtk/DecorationLayout from wm preferences

GTK+'s client-side decorations follow an XSetting to determine
which standard window buttons to show, similar to mutter's
button-layout setting in org.gnome.desktop.wm.preferences.
Keeping both mechanisms completely separate obviously means we
can end up with unwanted inconsistency, so use the GSetting
to back the XSetting on GNOME, just like we already do for
other settings (though it's a bit more involved, as the
possible values differ between mutter and GTK+).

https://bugzilla.gnome.org/show_bug.cgi?id=730629
---
 plugins/xsettings/Makefile.am                      | 21 ++++++
 plugins/xsettings/gsd-xsettings-manager.c          | 25 +++++-
 .../xsettings/test-wm-button-layout-translations.c | 54 +++++++++++++
 plugins/xsettings/wm-button-layout-translation.c   | 88 ++++++++++++++++++++++
 plugins/xsettings/wm-button-layout-translation.h   | 26 +++++++
 6 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100644 plugins/xsettings/test-wm-button-layout-translations.c
 create mode 100644 plugins/xsettings/wm-button-layout-translation.c
 create mode 100644 plugins/xsettings/wm-button-layout-translation.h

diff --git a/plugins/xsettings/Makefile.am b/plugins/xsettings/Makefile.am
index 467fc85..d068daa 100644
--- a/plugins/xsettings/Makefile.am
+++ b/plugins/xsettings/Makefile.am
@@ -27,6 +27,23 @@ test_gtk_modules_CPPFLAGS =				\
 	-DGTK_MODULES_DIRECTORY=\""$(libdir)/gnome-settings-daemon-@GSD_API_VERSION@/gtk-modules/"\" \
 	$(AM_CPPFLAGS)
 
+noinst_PROGRAMS += test-wm-button-layout-translations
+
+test_wm_button_layout_translations_SOURCES =	\
+	test-wm-button-layout-translations.c	\
+	wm-button-layout-translation.c		\
+	wm-button-layout-translation.h		\
+	$(NULL)
+
+test_wm_button_layout_translations_CFLAGS =	\
+	$(XSETTINGS_CFLAGS)			\
+	$(AM_CFLAGS)				\
+	$(NULL)
+
+test_wm_button_layout_translations_LDADD =	\
+	$(XSETTINGS_LIBS)			\
+	$(NULL)
+
 libexec_PROGRAMS = gsd-test-xsettings
 
 gsd_test_xsettings_SOURCES =	\
@@ -40,6 +57,8 @@ gsd_test_xsettings_SOURCES =	\
 	xsettings-manager.h	\
 	fontconfig-monitor.c	\
 	fontconfig-monitor.h	\
+	wm-button-layout-translation.c	\
+	wm-button-layout-translation.h	\
 	test-xsettings.c
 
 gsd_test_xsettings_CFLAGS = $(test_gtk_modules_CFLAGS)
@@ -62,6 +81,8 @@ libxsettings_la_SOURCES = 	\
 	xsettings-manager.c	\
 	fontconfig-monitor.h	\
 	fontconfig-monitor.c	\
+	wm-button-layout-translation.c	\
+	wm-button-layout-translation.h	\
 	$(NULL)
 
 libxsettings_la_CPPFLAGS =					\
diff --git a/plugins/xsettings/gsd-xsettings-manager.c b/plugins/xsettings/gsd-xsettings-manager.c
index cad40d0..7b8d0a1 100644
--- a/plugins/xsettings/gsd-xsettings-manager.c
+++ b/plugins/xsettings/gsd-xsettings-manager.c
@@ -44,6 +44,7 @@
 #include "gsd-xsettings-gtk.h"
 #include "xsettings-manager.h"
 #include "fontconfig-monitor.h"
+#include "wm-button-layout-translation.h"
 
 #define GNOME_XSETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_XSETTINGS_MANAGER, GnomeXSettingsManagerPrivate))
 
@@ -51,6 +52,7 @@
 #define INTERFACE_SETTINGS_SCHEMA "org.gnome.desktop.interface"
 #define SOUND_SETTINGS_SCHEMA     "org.gnome.desktop.sound"
 #define PRIVACY_SETTINGS_SCHEMA     "org.gnome.desktop.privacy"
+#define WM_SETTINGS_SCHEMA        "org.gnome.desktop.wm.preferences"
 
 #define XSETTINGS_PLUGIN_SCHEMA "org.gnome.settings-daemon.plugins.xsettings"
 #define XSETTINGS_OVERRIDE_KEY  "overrides"
@@ -321,6 +323,24 @@ translate_string_string (GnomeXSettingsManager *manager,
 }
 
 static void
+translate_button_layout (GnomeXSettingsManager *manager,
+                         TranslationEntry      *trans,
+                         GVariant              *value)
+{
+        char *layout = g_variant_dup_string (value, NULL);
+        int i;
+
+        translate_wm_button_layout_to_gtk (layout);
+
+        for (i = 0; manager->priv->managers [i]; i++)
+                xsettings_manager_set_string (manager->priv->managers [i],
+                                              trans->xsetting_name,
+                                              layout);
+
+        g_free (layout);
+}
+
+static void
 fixed_false_int (GnomeXSettingsManager *manager,
                  FixedEntry            *fixed)
 {
@@ -382,7 +402,8 @@ static TranslationEntry translations [] = {
         { "org.gnome.desktop.sound", "input-feedback-sounds",      "Net/EnableInputFeedbackSounds", translate_bool_int },
 
         { "org.gnome.desktop.privacy", "recent-files-max-age",      "Gtk/RecentFilesMaxAge", translate_int_int },
-        { "org.gnome.desktop.privacy", "remember-recent-files",    "Gtk/RecentFilesEnabled", translate_bool_int }
+        { "org.gnome.desktop.privacy", "remember-recent-files",    "Gtk/RecentFilesEnabled", translate_bool_int },
+        { "org.gnome.desktop.wm.preferences", "button-layout",     "Gtk/DecorationLayout", translate_button_layout }
 };
 
 static gboolean
@@ -970,6 +991,8 @@ gnome_xsettings_manager_start (GnomeXSettingsManager *manager,
                              SOUND_SETTINGS_SCHEMA, g_settings_new (SOUND_SETTINGS_SCHEMA));
         g_hash_table_insert (manager->priv->settings,
                              PRIVACY_SETTINGS_SCHEMA, g_settings_new (PRIVACY_SETTINGS_SCHEMA));
+        g_hash_table_insert (manager->priv->settings,
+                             WM_SETTINGS_SCHEMA, g_settings_new (WM_SETTINGS_SCHEMA));
 
         for (i = 0; i < G_N_ELEMENTS (fixed_entries); i++) {
                 FixedEntry *fixed = &fixed_entries[i];
diff --git a/plugins/xsettings/test-wm-button-layout-translations.c b/plugins/xsettings/test-wm-button-layout-translations.c
new file mode 100644
index 0000000..5ab140a
--- /dev/null
+++ b/plugins/xsettings/test-wm-button-layout-translations.c
@@ -0,0 +1,54 @@
+#include <glib.h>
+
+#include "wm-button-layout-translation.h"
+
+static void
+test_button_layout_translations (void)
+{
+  static struct {
+    char *layout;
+    char *expected;
+  } tests[] = {
+    { "", "" },
+    { "invalid", "" },
+
+    { ":", ":" },
+    { ":invalid", ":" },
+    { "invalid:", ":" },
+    { "invalid:invalid", ":" },
+
+    { "appmenu", "menu" },
+    { "appmenu:", "menu:" },
+    { ":menu", ":icon" },
+    { "appmenu:close", "menu:close" },
+    { "appmenu:minimize,maximize,close", "menu:minimize,maximize,close" },
+    { "menu,appmenu:minimize,maximize,close", "icon,menu:minimize,maximize,close" },
+
+    { "close,close,close:close,close,close", "close,close,close:close,close,close" },
+
+    { "invalid,appmenu:invalid,minimize", "menu:minimize" },
+    { "appmenu,invalid:minimize,invalid", "menu:minimize" },
+    { "invalidmenu:invalidclose", ":" },
+    { "invalid,invalid,invalid:invalid,minimize,maximize,close", ":minimize,maximize,close" },
+  };
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (tests); i++)
+    {
+      char *layout = g_strdup (tests[i].layout);
+
+      translate_wm_button_layout_to_gtk (layout);
+      g_assert_cmpstr (layout, ==, tests[i].expected);
+      g_free (layout);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/layout-translations", test_button_layout_translations);
+
+  return g_test_run ();
+}
diff --git a/plugins/xsettings/wm-button-layout-translation.c b/plugins/xsettings/wm-button-layout-translation.c
new file mode 100644
index 0000000..0fa4d2c
--- /dev/null
+++ b/plugins/xsettings/wm-button-layout-translation.c
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author:  Florian Müllner <fmuellner@gnome.org>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+#include "wm-button-layout-translation.h"
+
+static void
+translate_buttons (char *layout, int *len_p)
+{
+  char *strp = layout, *button;
+  int len = 0;
+
+  if (!layout || !*layout)
+    goto out;
+
+  while ((button = strsep (&strp, ",")))
+    {
+      char *gtkbutton;
+
+      if (strcmp (button, "menu") == 0)
+        gtkbutton = "icon";
+      else if (strcmp (button, "appmenu") == 0)
+        gtkbutton = "menu";
+      else if (strcmp (button, "minimize") == 0)
+        gtkbutton = "minimize";
+      else if (strcmp (button, "maximize") == 0)
+        gtkbutton = "maximize";
+      else if  (strcmp (button, "close") == 0)
+        gtkbutton = "close";
+      else
+        continue;
+
+      if (len)
+        layout[len++] = ',';
+
+      strcpy (layout + len, gtkbutton);
+      len += strlen (gtkbutton);
+    }
+  layout[len] = '\0';
+
+out:
+  if (len_p)
+    *len_p = len;
+}
+
+void
+translate_wm_button_layout_to_gtk (char *layout)
+{
+  char *strp = layout, *left_buttons, *right_buttons;
+  int left_len, right_len = 0;
+
+  left_buttons = strsep (&strp, ":");
+  right_buttons = strp;
+
+  translate_buttons (left_buttons, &left_len);
+  memmove (layout, left_buttons, left_len);
+
+  if (strp == NULL)
+    goto out; /* no ":" in layout */
+
+  layout[left_len++] = ':';
+
+  translate_buttons (right_buttons, &right_len);
+  memmove (layout + left_len, right_buttons, right_len);
+
+out:
+  layout[left_len + right_len] = '\0';
+}
diff --git a/plugins/xsettings/wm-button-layout-translation.h b/plugins/xsettings/wm-button-layout-translation.h
new file mode 100644
index 0000000..87210b6
--- /dev/null
+++ b/plugins/xsettings/wm-button-layout-translation.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author:  Florian Müllner <fmuellner@gnome.org>
+ */
+
+#ifndef __WM_BUTTON_LAYOUT_TRANSLATION__
+#define __WM_BUTTON_LAYOUT_TRANSLATION__
+
+void translate_wm_button_layout_to_gtk (char *layout);
+
+#endif
-- 
1.8.4.5


From 83d22d2f0252ddfe274cf03bac0874a9c9daa19f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 29 May 2014 19:11:50 +0200
Subject: [PATCH 2/4] xsettings: Explicitly handle classic mode for now

There are plans to add session-dependent defaults to GSettings
(based on the newly standardized XDG_CURRENT_DESKTOP); until
then, the WM uses a different schema for its button-layout
setting in classic mode. So for the time being, do the same
and pick the alternative schema when XDG_CURRENT_DESKTOP
indicates that we are in a classic session.
(It's not pretty, but hopefully won't be with us for too long ...)

https://bugzilla.gnome.org/show_bug.cgi?id=730629
---
 plugins/xsettings/gsd-xsettings-manager.c | 37 ++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/plugins/xsettings/gsd-xsettings-manager.c b/plugins/xsettings/gsd-xsettings-manager.c
index 7b8d0a1..ff3d733 100644
--- a/plugins/xsettings/gsd-xsettings-manager.c
+++ b/plugins/xsettings/gsd-xsettings-manager.c
@@ -53,6 +53,7 @@
 #define SOUND_SETTINGS_SCHEMA     "org.gnome.desktop.sound"
 #define PRIVACY_SETTINGS_SCHEMA     "org.gnome.desktop.privacy"
 #define WM_SETTINGS_SCHEMA        "org.gnome.desktop.wm.preferences"
+#define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides"
 
 #define XSETTINGS_PLUGIN_SCHEMA "org.gnome.settings-daemon.plugins.xsettings"
 #define XSETTINGS_OVERRIDE_KEY  "overrides"
@@ -327,9 +328,26 @@ translate_button_layout (GnomeXSettingsManager *manager,
                          TranslationEntry      *trans,
                          GVariant              *value)
 {
-        char *layout = g_variant_dup_string (value, NULL);
+        GSettings *classic_settings;
+        GVariant *classic_value = NULL;
+        const char *session;
+        char *layout;
         int i;
 
+        /* Hack: until we get session-dependent defaults in GSettings,
+         *       swap out the usual schema for the "classic" one when
+         *       running in classic mode
+         */
+        session = g_getenv ("XDG_CURRENT_DESKTOP");
+        classic_settings = g_hash_table_lookup (manager->priv->settings,
+                                                CLASSIC_WM_SETTINGS_SCHEMA);
+        if (session && strstr (session, "GNOME-Classic") && classic_settings) {
+                classic_value = g_settings_get_value (classic_settings, "button-layout");
+                layout = g_variant_dup_string (classic_value, NULL);
+        } else {
+                layout = g_variant_dup_string (value, NULL);
+        }
+
         translate_wm_button_layout_to_gtk (layout);
 
         for (i = 0; manager->priv->managers [i]; i++)
@@ -337,6 +355,8 @@ translate_button_layout (GnomeXSettingsManager *manager,
                                               trans->xsetting_name,
                                               layout);
 
+        if (classic_value)
+                g_variant_unref (classic_value);
         g_free (layout);
 }
 
@@ -846,6 +866,11 @@ find_translation_entry (GSettings *settings, const char *key)
 
         g_object_get (settings, "schema", &schema, NULL);
 
+        if (g_str_equal (schema, CLASSIC_WM_SETTINGS_SCHEMA)) {
+              g_free (schema);
+              schema = g_strdup (WM_SETTINGS_SCHEMA);
+        }
+
         for (i = 0; i < G_N_ELEMENTS (translations); i++) {
                 if (g_str_equal (schema, translations[i].gsettings_schema) &&
                     g_str_equal (key, translations[i].gsettings_key)) {
@@ -966,6 +991,7 @@ gboolean
 gnome_xsettings_manager_start (GnomeXSettingsManager *manager,
                                GError               **error)
 {
+        GSettingsSchema *schema;
         GVariant    *overrides;
         guint        i;
         GList       *list, *l;
@@ -994,6 +1020,15 @@ gnome_xsettings_manager_start (GnomeXSettingsManager *manager,
         g_hash_table_insert (manager->priv->settings,
                              WM_SETTINGS_SCHEMA, g_settings_new (WM_SETTINGS_SCHEMA));
 
+        schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+                                                  CLASSIC_WM_SETTINGS_SCHEMA, FALSE);
+        if (schema) {
+                g_hash_table_insert (manager->priv->settings,
+                                     CLASSIC_WM_SETTINGS_SCHEMA,
+                                     g_settings_new_full (schema, NULL, NULL));
+                g_settings_schema_unref (schema);
+        }
+
         for (i = 0; i < G_N_ELEMENTS (fixed_entries); i++) {
                 FixedEntry *fixed = &fixed_entries[i];
                 (* fixed->func) (manager, fixed);
-- 
1.8.4.5


From 72556ab762243a7fd388590bde1267230a4173c7 Mon Sep 17 00:00:00 2001
From: Federico Mena Quintero <federico@gnome.org>
Date: Fri, 15 Aug 2014 14:53:42 -0500
Subject: [PATCH 3/4] Require gnome-desktop to build the xsettings plugin

We need some libraries for that test program.
---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 9f3b7ed..05cc224 100644
--- a/configure.ac
+++ b/configure.ac
@@ -173,7 +173,7 @@ dnl ---------------------------------------------------------------------------
 dnl - xsettings
 dnl ---------------------------------------------------------------------------
 
-PKG_CHECK_MODULES(XSETTINGS, fontconfig)
+PKG_CHECK_MODULES(XSETTINGS, fontconfig gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
 
 dnl ---------------------------------------------------------------------------
 dnl - Keyboard plugin stuff
-- 
1.8.4.5


From 1cc1e1cce9a615c115b5408242d972dfccae6c22 Mon Sep 17 00:00:00 2001
From: Federico Mena Quintero <federico@gnome.org>
Date: Thu, 25 Sep 2014 20:33:57 -0500
Subject: [PATCH 4/4] Use GNOME_SHELL_SESSION_MODE to determine if we are in
 classic mode, not XDG_CURRENT_DESKTOP

In GNOME 3.10, we don't have the XDG_CURRENT_DESKTOP environment variable.
---
 plugins/xsettings/gsd-xsettings-manager.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/plugins/xsettings/gsd-xsettings-manager.c b/plugins/xsettings/gsd-xsettings-manager.c
index ff3d733..6bc028b 100644
--- a/plugins/xsettings/gsd-xsettings-manager.c
+++ b/plugins/xsettings/gsd-xsettings-manager.c
@@ -338,10 +338,10 @@ translate_button_layout (GnomeXSettingsManager *manager,
          *       swap out the usual schema for the "classic" one when
          *       running in classic mode
          */
-        session = g_getenv ("XDG_CURRENT_DESKTOP");
+        session = g_getenv ("GNOME_SHELL_SESSION_MODE");
         classic_settings = g_hash_table_lookup (manager->priv->settings,
                                                 CLASSIC_WM_SETTINGS_SCHEMA);
-        if (session && strstr (session, "GNOME-Classic") && classic_settings) {
+        if (session && strstr (session, "classic") && classic_settings) {
                 classic_value = g_settings_get_value (classic_settings, "button-layout");
                 layout = g_variant_dup_string (classic_value, NULL);
         } else {
-- 
1.8.4.5

