summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaakov Selkowitz <yselkowi@redhat.com>2015-07-13 00:04:28 -0500
committerYaakov Selkowitz <yselkowi@redhat.com>2015-07-13 00:04:28 -0500
commitff4e901743fa0e0bad54c525523a2960f916455b (patch)
tree2db6e00009e92056f0a48f559b7f31a089a96992
parent6340fdbeea65e26fb879e3466d12668ae06bde3c (diff)
downloadgnome-flashback-ff4e901743fa0e0bad54c525523a2960f916455b.tar.gz
gnome-flashback-ff4e901743fa0e0bad54c525523a2960f916455b.tar.xz
gnome-flashback-ff4e901743fa0e0bad54c525523a2960f916455b.zip
Backport upstream fix for BGO#738562
-rw-r--r--0001-workarounds-add-app-menu-and-button-layout-workaroun.patch1035
-rw-r--r--gnome-flashback-wm-prefs-overrides.patch19
-rw-r--r--gnome-flashback.spec10
3 files changed, 1042 insertions, 22 deletions
diff --git a/0001-workarounds-add-app-menu-and-button-layout-workaroun.patch b/0001-workarounds-add-app-menu-and-button-layout-workaroun.patch
new file mode 100644
index 0000000..ba789de
--- /dev/null
+++ b/0001-workarounds-add-app-menu-and-button-layout-workaroun.patch
@@ -0,0 +1,1035 @@
+From 4ac240d28b613499c49487b9f6280108055948a4 Mon Sep 17 00:00:00 2001
+From: Yaakov Selkowitz <yselkowi@redhat.com>
+Date: Sun, 12 Jul 2015 23:48:16 -0500
+Subject: [PATCH] workarounds: add app-menu and button-layout workarounds
+
+fix-app-menu: if enabled gnome-flashback will set
+Gtk/ShellShowsAppMenu to FALSE.
+
+fix-button-layout: if enabled gnome-flashback will set
+Gtk/DecorationLayout to value set in this setting. To disable this
+workaround set it to empty string.
+
+NOTE: It is not possible to use Gtk/ShellShowsAppMenu and
+Gtk/DecorationLayout as overrides in xsettings plugin in
+gnome-settings-daemon. gnome-flashback will override these
+properties.
+
+Backports of following commits to gnome-3-14:
+f0ec5b40f5f0cfc23e6d101428fb7d85ed5892b7
+69b07b0f58494fd5a64fa9c59550544efd9b2215
+018268113a857f24f9c1c7863510007266cb18c8
+f6cb156d92cc1997918e66823e305bf8d5301d31
+---
+ configure.ac | 5 +
+ data/org.gnome.gnome-flashback.gschema.xml.in.in | 19 +
+ gnome-flashback/Makefile.am | 10 +-
+ gnome-flashback/flashback-application.c | 14 +
+ gnome-flashback/libworkarounds/Makefile.am | 21 +
+ .../libworkarounds/flashback-workarounds.c | 765 +++++++++++++++++++++
+ .../libworkarounds/flashback-workarounds.h | 50 ++
+ 7 files changed, 882 insertions(+), 2 deletions(-)
+ create mode 100644 gnome-flashback/libworkarounds/Makefile.am
+ create mode 100644 gnome-flashback/libworkarounds/flashback-workarounds.c
+ create mode 100644 gnome-flashback/libworkarounds/flashback-workarounds.h
+
+diff --git a/configure.ac b/configure.ac
+index 412efe8..f4f853e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -64,6 +64,10 @@ PKG_CHECK_MODULES(SOUND_APPLET, gtk+-3.0 >= $GTK_REQUIRED libcanberra-gtk3 >= $C
+ AC_SUBST(SOUND_APPLET_CFLAGS)
+ AC_SUBST(SOUND_APPLET_LIBS)
+
++PKG_CHECK_MODULES(WORKAROUNDS, glib-2.0 >= $GLIB_REQUIRED gtk+-3.0 >= $GTK_REQUIRED x11)
++AC_SUBST(WORKAROUNDS_CFLAGS)
++AC_SUBST(WORKAROUNDS_LIBS)
++
+ AC_CONFIG_FILES([
+ Makefile
+ data/Makefile
+@@ -75,6 +79,7 @@ gnome-flashback/libend-session-dialog/Makefile
+ gnome-flashback/libidle-monitor/Makefile
+ gnome-flashback/libsound-applet/Makefile
+ gnome-flashback/libsound-applet/gvc/Makefile
++gnome-flashback/libworkarounds/Makefile
+ po/Makefile.in
+ ])
+
+diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in b/data/org.gnome.gnome-flashback.gschema.xml.in.in
+index 5c766a2..7fe3b42 100644
+--- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
++++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
+@@ -30,8 +30,14 @@
+ <_summary>Sound applet</_summary>
+ <_description>If set to true, then GNOME Flashback application will be used to show sound applet. This is same sound applet that used to be part of GNOME Control Center.</_description>
+ </key>
++ <key name="workarounds" type="b">
++ <default>true</default>
++ <_summary>Workarounds</_summary>
++ <_description>If set to true, then GNOME Flashback application will use workarounds to fix bugs.</_description>
++ </key>
+
+ <child name="desktop-background" schema="org.gnome.gnome-flashback.desktop-background"/>
++ <child name="workarounds" schema="org.gnome.gnome-flashback.workarounds"/>
+ </schema>
+
+ <schema id="org.gnome.gnome-flashback.desktop-background" path="/org/gnome/gnome-flashback/desktop-background/">
+@@ -41,4 +47,17 @@
+ <_description>If set to true, then fade effect will be used to change the desktop background.</_description>
+ </key>
+ </schema>
++
++ <schema id="org.gnome.gnome-flashback.workarounds" path="/org/gnome/gnome-flashback/workarounds/">
++ <key name="fix-app-menu" type="b">
++ <default>true</default>
++ <_summary>Fix missing app menu button</_summary>
++ <_description>If set to true, then gnome-flashback will force Gtk/ShellShowsAppMenu to FALSE. Disable if you want to use gnome-settings-daemon overrides in xsettings plugin for 'Gtk/ShellShowsAppMenu' property.</_description>
++ </key>
++ <key name="fix-button-layout" type="s">
++ <default>'menu:minimize,maximize,close'</default>
++ <_summary>Fix wrong button layout</_summary>
++ <_description>If set to non-empty string, then gnome-flashback will force Gtk/DecorationLayout to value set by this setting. Set to empty string if you want to use gnome-settings-daemon overrides in xsettings plugin for 'Gtk/DecorationLayout' property.</_description>
++ </key>
++ </schema>
+ </schemalist>
+diff --git a/gnome-flashback/Makefile.am b/gnome-flashback/Makefile.am
+index 3a10388..c568d37 100644
+--- a/gnome-flashback/Makefile.am
++++ b/gnome-flashback/Makefile.am
+@@ -1,10 +1,14 @@
++NULL =
++
+ SUBDIRS = \
+ libautomount-manager \
+ libdesktop-background \
+ libdisplay-config \
+ libend-session-dialog \
+ libidle-monitor \
+- libsound-applet
++ libsound-applet \
++ libworkarounds \
++ $(NULL)
+
+ bin_PROGRAMS = \
+ gnome-flashback
+@@ -28,6 +32,8 @@ gnome_flashback_LDADD = \
+ $(top_builddir)/gnome-flashback/libdisplay-config/libdisplay-config.la \
+ $(top_builddir)/gnome-flashback/libend-session-dialog/libend-session-dialog.la \
+ $(top_builddir)/gnome-flashback/libidle-monitor/libidle-monitor.la \
+- $(top_builddir)/gnome-flashback/libsound-applet/libsound-applet.la
++ $(top_builddir)/gnome-flashback/libsound-applet/libsound-applet.la \
++ $(top_builddir)/gnome-flashback/libworkarounds/libworkarounds.la \
++ $(NULL)
+
+ -include $(top_srcdir)/git.mk
+diff --git a/gnome-flashback/flashback-application.c b/gnome-flashback/flashback-application.c
+index 3153128..5a9f098 100644
+--- a/gnome-flashback/flashback-application.c
++++ b/gnome-flashback/flashback-application.c
+@@ -25,6 +25,7 @@
+ #include "libend-session-dialog/flashback-end-session-dialog.h"
+ #include "libidle-monitor/meta-idle-monitor-dbus.h"
+ #include "libsound-applet/gvc-applet.h"
++#include "libworkarounds/flashback-workarounds.h"
+
+ #define FLASHBACK_SCHEMA "org.gnome.gnome-flashback"
+ #define KEY_AUTOMOUNT_MANAGER "automount-manager"
+@@ -33,6 +34,7 @@
+ #define KEY_END_SESSION_DIALOG "end-session-dialog"
+ #define KEY_IDLE_MONITOR "idle-monitor"
+ #define KEY_SOUND_APPLET "sound-applet"
++#define KEY_WORKAROUNDS "workarounds"
+
+ struct _FlashbackApplicationPrivate {
+ GSettings *settings;
+@@ -42,6 +44,7 @@ struct _FlashbackApplicationPrivate {
+ FlashbackEndSessionDialog *dialog;
+ MetaIdleMonitorDBus *idle_monitor;
+ GvcApplet *applet;
++ FlashbackWorkarounds *workarounds;
+ };
+
+ G_DEFINE_TYPE_WITH_PRIVATE (FlashbackApplication, flashback_application, G_TYPE_OBJECT);
+@@ -115,6 +118,16 @@ flashback_application_settings_changed (GSettings *settings,
+ g_clear_object (&app->priv->applet);
+ }
+ }
++
++ if (key == NULL || g_strcmp0 (key, KEY_WORKAROUNDS) == 0) {
++ if (g_settings_get_boolean (settings, KEY_WORKAROUNDS)) {
++ if (app->priv->workarounds == NULL) {
++ app->priv->workarounds = flashback_workarounds_new ();
++ }
++ } else {
++ g_clear_object (&app->priv->workarounds);
++ }
++ }
+ }
+
+ static void
+@@ -127,6 +140,7 @@ flashback_application_finalize (GObject *object)
+ g_clear_object (&app->priv->dialog);
+ g_clear_object (&app->priv->idle_monitor);
+ g_clear_object (&app->priv->applet);
++ g_clear_object (&app->priv->workarounds);
+ g_clear_object (&app->priv->settings);
+
+ G_OBJECT_CLASS (flashback_application_parent_class)->finalize (object);
+diff --git a/gnome-flashback/libworkarounds/Makefile.am b/gnome-flashback/libworkarounds/Makefile.am
+new file mode 100644
+index 0000000..6cfc453
+--- /dev/null
++++ b/gnome-flashback/libworkarounds/Makefile.am
+@@ -0,0 +1,21 @@
++NULL =
++
++noinst_LTLIBRARIES = \
++ libworkarounds.la \
++ $(NULL)
++
++AM_CPPFLAGS = \
++ $(WORKAROUNDS_CFLAGS) \
++ -I$(top_builddir)/gnome-flashback/libworkarounds \
++ $(NULL)
++
++libworkarounds_la_SOURCES = \
++ flashback-workarounds.c \
++ flashback-workarounds.h \
++ $(NULL)
++
++libworkarounds_la_LIBADD = \
++ $(WORKAROUNDS_LIBS) \
++ $(NULL)
++
++-include $(top_srcdir)/git.mk
+diff --git a/gnome-flashback/libworkarounds/flashback-workarounds.c b/gnome-flashback/libworkarounds/flashback-workarounds.c
+new file mode 100644
+index 0000000..39fdfbb
+--- /dev/null
++++ b/gnome-flashback/libworkarounds/flashback-workarounds.c
+@@ -0,0 +1,765 @@
++/*
++ * Copyright (C) 2015 Alberts Muktupāvels
++ *
++ * 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 3 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/>.
++ *
++ * Based on code from Owen Taylor, Copyright(C) 2001, 2007 Red Hat, Inc.
++ *
++ * https://git.gnome.org/browse/gtk+/tree/gdk/x11/xsettings-client.c
++ * https://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/xsettings-manager.c
++ */
++
++#include "config.h"
++
++#include <string.h>
++#include <gdk/gdkx.h>
++#include <gtk/gtk.h>
++#include <X11/Xmd.h>
++
++#include "flashback-workarounds.h"
++
++#define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos)
++#define RETURN_IF_FAIL_BYTES(buffer, n_bytes) if (BYTES_LEFT (buffer) < (n_bytes)) return FALSE;
++#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
++
++struct _FlashbackWorkaroundsPrivate
++{
++ GSettings *g_settings;
++ GtkSettings *gtk_settings;
++
++ gboolean fix_app_menu;
++ gchar *fix_button_layout;
++
++ guint idle_id;
++ guint timeout_id;
++
++ Display *xdisplay;
++
++ Atom selection_atom;
++ Atom xsettings_atom;
++
++ Window manager_window;
++
++ GHashTable *xsettings;
++ CARD32 serial;
++};
++
++G_DEFINE_TYPE_WITH_PRIVATE (FlashbackWorkarounds, flashback_workarounds, G_TYPE_OBJECT)
++
++static void add_workarounds (FlashbackWorkarounds *workarounds);
++
++typedef enum
++{
++ XSETTINGS_TYPE_INT = 0,
++ XSETTINGS_TYPE_STRING = 1,
++ XSETTINGS_TYPE_COLOR = 2
++} XSettingsType;
++
++typedef struct
++{
++ gchar *name;
++ XSettingsType type;
++ GValue *value;
++ gulong last_change_serial;
++} XSettingsSetting;
++
++typedef struct
++{
++ gchar byte_order;
++ gulong len;
++ guchar *data;
++ guchar *pos;
++} XSettingsBuffer;
++
++static gboolean
++fetch_card16 (XSettingsBuffer *buffer,
++ CARD16 *result)
++{
++ CARD16 x;
++
++ RETURN_IF_FAIL_BYTES (buffer, 2);
++
++ x = *(CARD16 *)buffer->pos;
++ buffer->pos += 2;
++
++ if (buffer->byte_order == MSBFirst)
++ *result = GUINT16_FROM_BE (x);
++ else
++ *result = GUINT16_FROM_LE (x);
++
++ return TRUE;
++}
++
++static gboolean
++fetch_ushort (XSettingsBuffer *buffer,
++ gushort *result)
++{
++ CARD16 x;
++ gboolean r;
++
++ r = fetch_card16 (buffer, &x);
++ if (r)
++ *result = x;
++
++ return r;
++}
++
++static gboolean
++fetch_card32 (XSettingsBuffer *buffer,
++ CARD32 *result)
++{
++ CARD32 x;
++
++ RETURN_IF_FAIL_BYTES (buffer, 4);
++
++ x = *(CARD32 *)buffer->pos;
++ buffer->pos += 4;
++
++ if (buffer->byte_order == MSBFirst)
++ *result = GUINT32_FROM_BE (x);
++ else
++ *result = GUINT32_FROM_LE (x);
++
++ return TRUE;
++}
++
++static gboolean
++fetch_card8 (XSettingsBuffer *buffer,
++ CARD8 *result)
++{
++ RETURN_IF_FAIL_BYTES (buffer, 1);
++
++ *result = *(CARD8 *)buffer->pos;
++ buffer->pos += 1;
++
++ return TRUE;
++}
++
++static gboolean
++fetch_string (XSettingsBuffer *buffer,
++ guint length,
++ gchar **result)
++{
++ guint pad_len;
++
++ pad_len = XSETTINGS_PAD (length, 4);
++ if (pad_len < length)
++ return FALSE;
++
++ RETURN_IF_FAIL_BYTES (buffer, pad_len);
++
++ *result = g_strndup ((gchar *) buffer->pos, length);
++ buffer->pos += pad_len;
++
++ return TRUE;
++}
++
++static void
++free_gvalue (gpointer user_data)
++{
++ GValue *value;
++
++ value = (GValue *) user_data;
++
++ g_value_unset (value);
++ g_free (value);
++}
++
++static void
++free_xsetting (gpointer data)
++{
++ XSettingsSetting *setting;
++
++ setting = (XSettingsSetting *) data;
++
++ g_free (setting->name);
++ free_gvalue (setting->value);
++ g_free (setting);
++}
++
++static GHashTable *
++parse_settings (FlashbackWorkarounds *workarounds,
++ guchar *data,
++ gulong n_items)
++{
++ XSettingsBuffer buffer;
++ GHashTable *settings;
++ CARD32 n_entries;
++ CARD32 i;
++ GValue *value;
++ gchar *x_name;
++ gulong last_change_serial;
++ XSettingsSetting *setting;
++
++ buffer.pos = buffer.data = data;
++ buffer.len = n_items;
++
++ if (!fetch_card8 (&buffer, (guchar *)&buffer.byte_order))
++ return NULL;
++
++ if (buffer.byte_order != MSBFirst && buffer.byte_order != LSBFirst)
++ return NULL;
++
++ buffer.pos += 3;
++
++ if (!fetch_card32 (&buffer, &workarounds->priv->serial) ||
++ !fetch_card32 (&buffer, &n_entries))
++ return NULL;
++
++ settings = NULL;
++ value = NULL;
++ x_name = NULL;
++
++ for (i = 0; i < n_entries; i++)
++ {
++ CARD8 type;
++ CARD16 name_len;
++ CARD32 v_int;
++
++ if (!fetch_card8 (&buffer, &type))
++ goto out;
++
++ buffer.pos += 1;
++
++ if (!fetch_card16 (&buffer, &name_len))
++ goto out;
++
++ if (!fetch_string (&buffer, name_len, &x_name) || !fetch_card32 (&buffer, &v_int))
++ goto out;
++
++ last_change_serial = (gulong) v_int;
++
++ switch (type)
++ {
++ case XSETTINGS_TYPE_INT:
++ if (!fetch_card32 (&buffer, &v_int))
++ goto out;
++
++ value = g_new0 (GValue, 1);
++ g_value_init (value, G_TYPE_INT);
++ g_value_set_int (value, (gint32) v_int);
++ break;
++
++ case XSETTINGS_TYPE_STRING:
++ {
++ gchar *s;
++
++ if (!fetch_card32 (&buffer, &v_int) || !fetch_string (&buffer, v_int, &s))
++ goto out;
++
++ value = g_new0 (GValue, 1);
++ g_value_init (value, G_TYPE_STRING);
++ g_value_take_string (value, s);
++ }
++ break;
++
++ case XSETTINGS_TYPE_COLOR:
++ /* GNOME Settings Daemon does not export settings with color type. */
++ g_free (x_name);
++ x_name = NULL;
++ break;
++
++ default:
++ /* Unknown type */
++ g_free (x_name);
++ x_name = NULL;
++ break;
++ }
++
++ if (settings == NULL)
++ settings = g_hash_table_new_full (g_str_hash, g_str_equal,
++ g_free, free_xsetting);
++
++ if (g_hash_table_lookup (settings, x_name) != NULL)
++ goto out;
++
++ if (x_name != NULL)
++ {
++ setting = g_new0 (XSettingsSetting, 1);
++
++ setting->name = g_strdup (x_name);
++ setting->type = type;
++ setting->value = value;
++ setting->last_change_serial = last_change_serial;
++
++ g_hash_table_insert (settings, (gpointer) x_name, setting);
++
++ x_name = NULL;
++ value = NULL;
++ }
++ }
++
++ return settings;
++
++out:
++
++ if (value)
++ free_gvalue (value);
++
++ if (settings)
++ g_hash_table_unref (settings);
++
++ g_free (x_name);
++
++ return NULL;
++}
++
++static gboolean
++read_settings (FlashbackWorkarounds *workarounds)
++{
++ GdkDisplay *display;
++ gint result;
++ Atom type;
++ gint format;
++ gulong n_items;
++ gulong bytes_after;
++ guchar *data;
++
++ display = gdk_x11_lookup_xdisplay (workarounds->priv->xdisplay);
++
++ gdk_x11_display_error_trap_push (display);
++ result = XGetWindowProperty (workarounds->priv->xdisplay, workarounds->priv->manager_window,
++ workarounds->priv->xsettings_atom, 0, LONG_MAX,
++ False, workarounds->priv->xsettings_atom,
++ &type, &format, &n_items, &bytes_after, &data);
++ gdk_x11_display_error_trap_pop_ignored (display);
++
++ if (result == Success && type != None)
++ {
++ if (type == workarounds->priv->xsettings_atom && format == 8)
++ workarounds->priv->xsettings = parse_settings (workarounds, data, n_items);
++
++ XFree (data);
++ }
++
++ if (workarounds->priv->xsettings)
++ return TRUE;
++
++ return FALSE;
++}
++
++static gchar
++get_byte_order (void)
++{
++ CARD32 myint = 0x01020304;
++ return (*(gchar *)&myint == 1) ? MSBFirst : LSBFirst;
++}
++
++static void
++align_string (GString *string,
++ gint alignment)
++{
++ while ((string->len % alignment) != 0)
++ g_string_append_c (string, '\0');
++}
++
++static void
++setting_store (XSettingsSetting *setting,
++ GString *buffer)
++{
++ guint16 len16;
++
++ g_string_append_c (buffer, setting->type);
++ g_string_append_c (buffer, 0);
++
++ len16 = strlen (setting->name);
++ g_string_append_len (buffer, (gchar *) &len16, 2);
++ g_string_append (buffer, setting->name);
++ align_string (buffer, 4);
++
++ g_string_append_len (buffer, (gchar *) &setting->last_change_serial, 4);
++
++ if (setting->type == XSETTINGS_TYPE_INT)
++ {
++ gint value;
++
++ value = g_value_get_int (setting->value);
++
++ g_string_append_len (buffer, (gchar *) &value, 4);
++ }
++ else if (setting->type == XSETTINGS_TYPE_STRING)
++ {
++ const gchar *string;
++ guint32 len32;
++
++ string = g_value_get_string (setting->value);
++ len32 = strlen (string);
++ g_string_append_len (buffer, (gchar *) &len32, 4);
++ g_string_append (buffer, string);
++ align_string (buffer, 4);
++ }
++ else if (setting->type == XSETTINGS_TYPE_COLOR)
++ {
++ /* GNOME Settings Daemon does not export settings with color type. */
++ }
++}
++
++static void
++write_settings (FlashbackWorkarounds *workarounds)
++{
++ GString *buffer;
++ GHashTableIter iter;
++ int n_settings;
++ gpointer value;
++
++ n_settings = g_hash_table_size (workarounds->priv->xsettings);
++
++ buffer = g_string_new (NULL);
++ g_string_append_c (buffer, get_byte_order ());
++ g_string_append_c (buffer, '\0');
++ g_string_append_c (buffer, '\0');
++ g_string_append_c (buffer, '\0');
++
++ g_string_append_len (buffer, (gchar *) &workarounds->priv->serial, 4);
++ g_string_append_len (buffer, (gchar *) &n_settings, 4);
++
++ g_hash_table_iter_init (&iter, workarounds->priv->xsettings);
++ while (g_hash_table_iter_next (&iter, NULL, &value))
++ setting_store (value, buffer);
++
++ XChangeProperty (workarounds->priv->xdisplay, workarounds->priv->manager_window,
++ workarounds->priv->xsettings_atom, workarounds->priv->xsettings_atom,
++ 8, PropModeReplace, (guchar *) buffer->str, buffer->len);
++
++ g_string_free (buffer, TRUE);
++ g_hash_table_unref (workarounds->priv->xsettings);
++ workarounds->priv->xsettings = NULL;
++}
++
++static void
++apply_app_menu_workaround (FlashbackWorkarounds *workarounds)
++{
++ const gchar *key;
++ XSettingsSetting *setting;
++
++ key = "Gtk/ShellShowsAppMenu";
++ setting = g_hash_table_lookup (workarounds->priv->xsettings, key);
++
++ if (setting != NULL)
++ {
++ g_hash_table_steal (workarounds->priv->xsettings, key);
++ free_gvalue (setting->value);
++ }
++ else
++ {
++ setting = g_new0 (XSettingsSetting, 1);
++ setting->name = g_strdup (key);
++ setting->type = XSETTINGS_TYPE_INT;
++ setting->last_change_serial = 0;
++ }
++
++ setting->value = g_new0 (GValue, 1);
++ g_value_init (setting->value, G_TYPE_INT);
++ g_value_set_int (setting->value, 0);
++
++ g_hash_table_insert (workarounds->priv->xsettings, g_strdup (key), setting);
++}
++
++static void
++apply_button_layout_workaround (FlashbackWorkarounds *workarounds)
++{
++ const gchar *key;
++ XSettingsSetting *setting;
++
++ key = "Gtk/DecorationLayout";
++ setting = g_hash_table_lookup (workarounds->priv->xsettings, key);
++
++ if (setting != NULL)
++ {
++ g_hash_table_steal (workarounds->priv->xsettings, key);
++ free_gvalue (setting->value);
++ }
++ else
++ {
++ setting = g_new0 (XSettingsSetting, 1);
++ setting->name = g_strdup (key);
++ setting->type = XSETTINGS_TYPE_STRING;
++ setting->last_change_serial = 0;
++ }
++
++ setting->value = g_new0 (GValue, 1);
++ g_value_init (setting->value, G_TYPE_STRING);
++ g_value_set_string (setting->value, workarounds->priv->fix_button_layout);
++
++ g_hash_table_insert (workarounds->priv->xsettings, g_strdup (key), setting);
++}
++
++static gboolean
++apply_workarounds (FlashbackWorkarounds *workarounds)
++{
++ gboolean gtk_shell_shows_app_menu;
++ gchar *gtk_decoration_layout;
++ gboolean need_workarounds;
++
++ g_object_get (workarounds->priv->gtk_settings,
++ "gtk-shell-shows-app-menu", &gtk_shell_shows_app_menu,
++ NULL);
++
++ g_object_get (workarounds->priv->gtk_settings,
++ "gtk-decoration-layout", &gtk_decoration_layout,
++ NULL);
++
++ need_workarounds = gtk_shell_shows_app_menu;
++ if (g_strcmp0 (gtk_decoration_layout, workarounds->priv->fix_button_layout) != 0)
++ need_workarounds = TRUE;
++
++ g_free (gtk_decoration_layout);
++
++ if (!need_workarounds)
++ return TRUE;
++
++ workarounds->priv->manager_window = XGetSelectionOwner (workarounds->priv->xdisplay,
++ workarounds->priv->selection_atom);
++
++ if (workarounds->priv->manager_window == None)
++ return FALSE;
++
++ if (!read_settings (workarounds))
++ return FALSE;
++
++ if (workarounds->priv->fix_app_menu)
++ apply_app_menu_workaround (workarounds);
++
++ if (g_strcmp0 (workarounds->priv->fix_button_layout, "") != 0)
++ apply_button_layout_workaround (workarounds);
++
++ write_settings (workarounds);
++
++ return TRUE;
++}
++
++static gboolean
++try_again (gpointer user_data)
++{
++ FlashbackWorkarounds *workarounds;
++
++ workarounds = FLASHBACK_WORKAROUNDS (user_data);
++
++ add_workarounds (workarounds);
++
++ workarounds->priv->timeout_id = 0;
++ return G_SOURCE_REMOVE;
++}
++
++static gboolean
++add_workarounds_real (gpointer user_data)
++{
++ FlashbackWorkarounds *workarounds;
++ gboolean fix_app_menu;
++ gchar *fix_button_layout;
++
++ workarounds = FLASHBACK_WORKAROUNDS (user_data);
++
++ fix_app_menu = g_settings_get_boolean (workarounds->priv->g_settings,
++ "fix-app-menu");
++ fix_button_layout = g_settings_get_string (workarounds->priv->g_settings,
++ "fix-button-layout");
++
++ g_free (workarounds->priv->fix_button_layout);
++
++ workarounds->priv->fix_app_menu = fix_app_menu;
++ workarounds->priv->fix_button_layout = fix_button_layout;
++
++ if (!fix_app_menu && g_strcmp0 (fix_button_layout, "") == 0)
++ {
++ workarounds->priv->idle_id = 0;
++ return G_SOURCE_REMOVE;
++ }
++
++ if (!apply_workarounds (workarounds))
++ {
++ if (workarounds->priv->timeout_id > 0)
++ g_source_remove (workarounds->priv->timeout_id);
++
++ workarounds->priv->timeout_id = g_timeout_add (100, try_again, workarounds);
++ g_source_set_name_by_id (workarounds->priv->timeout_id,
++ "[gnome-flashback] try_again");
++ }
++
++ workarounds->priv->idle_id = 0;
++ return G_SOURCE_REMOVE;
++}
++
++static void
++add_workarounds (FlashbackWorkarounds *workarounds)
++{
++ if (workarounds->priv->idle_id > 0)
++ g_source_remove (workarounds->priv->idle_id);
++
++ workarounds->priv->idle_id = g_idle_add (add_workarounds_real, workarounds);
++ g_source_set_name_by_id (workarounds->priv->idle_id,
++ "[gnome-flashback] add_workarounds_real");
++}
++
++static void
++remove_workarounds (void)
++{
++ GSettings *settings;
++ GVariant *overrides;
++
++ settings = g_settings_new ("org.gnome.settings-daemon.plugins.xsettings");
++
++ overrides = g_settings_get_value (settings, "overrides");
++ g_settings_set_value (settings, "overrides", overrides);
++
++ g_variant_unref (overrides);
++ g_object_unref (settings);
++}
++
++static void
++g_settings_changed (GSettings *settings,
++ const gchar *key,
++ gpointer user_data)
++{
++ FlashbackWorkarounds *workarounds;
++ gboolean fix_app_menu;
++ gchar *fix_button_layout;
++ gboolean reset;
++
++ workarounds = FLASHBACK_WORKAROUNDS (user_data);
++
++ fix_app_menu = g_settings_get_boolean (workarounds->priv->g_settings,
++ "fix-app-menu");
++ fix_button_layout = g_settings_get_string (workarounds->priv->g_settings,
++ "fix-button-layout");
++
++ reset = FALSE;
++
++ if (workarounds->priv->fix_app_menu && !fix_app_menu)
++ reset = TRUE;
++
++ if (g_strcmp0 (workarounds->priv->fix_button_layout, "") != 0 &&
++ g_strcmp0 (fix_button_layout, "") == 0)
++ reset = TRUE;
++
++ g_free (fix_button_layout);
++
++ if (reset)
++ {
++ remove_workarounds ();
++ return;
++ }
++
++ add_workarounds (workarounds);
++}
++
++static void
++gtk_settings_changed (GtkSettings *settings,
++ GParamSpec *pspec,
++ gpointer user_data)
++{
++ FlashbackWorkarounds *workarounds;
++
++ workarounds = FLASHBACK_WORKAROUNDS (user_data);
++
++ add_workarounds (workarounds);
++}
++
++static void
++x11_init (FlashbackWorkarounds *workarounds)
++{
++ GdkDisplay *display;
++ Display *xdisplay;
++ GdkScreen *screen;
++ gint number;
++ gchar *atom;
++
++ display = gdk_display_get_default ();
++ xdisplay = gdk_x11_display_get_xdisplay (display);
++ screen = gdk_display_get_default_screen (display);
++ number = gdk_screen_get_number (screen);
++ atom = g_strdup_printf ("_XSETTINGS_S%d", number);
++
++ workarounds->priv->xdisplay = xdisplay;
++ workarounds->priv->selection_atom = XInternAtom (xdisplay, atom, False);
++ workarounds->priv->xsettings_atom = XInternAtom (xdisplay, "_XSETTINGS_SETTINGS", False);
++
++ g_free (atom);
++}
++
++static void
++flashback_workarounds_finalize (GObject *object)
++{
++ FlashbackWorkarounds *workarounds;
++
++ workarounds = FLASHBACK_WORKAROUNDS (object);
++
++ g_clear_object (&workarounds->priv->g_settings);
++ g_signal_handlers_disconnect_by_func (workarounds->priv->gtk_settings,
++ gtk_settings_changed,
++ workarounds);
++
++ g_free (workarounds->priv->fix_button_layout);
++
++ if (workarounds->priv->idle_id > 0)
++ {
++ g_source_remove (workarounds->priv->idle_id);
++ workarounds->priv->idle_id = 0;
++ }
++
++ if (workarounds->priv->timeout_id > 0)
++ {
++ g_source_remove (workarounds->priv->timeout_id);
++ workarounds->priv->timeout_id = 0;
++ }
++
++ if (workarounds->priv->xsettings)
++ {
++ g_hash_table_unref (workarounds->priv->xsettings);
++ workarounds->priv->xsettings = NULL;
++ }
++
++ remove_workarounds ();
++
++ G_OBJECT_CLASS (flashback_workarounds_parent_class)->finalize (object);
++}
++
++static void
++flashback_workarounds_class_init (FlashbackWorkaroundsClass *class)
++{
++ GObjectClass *object_class;
++
++ object_class = G_OBJECT_CLASS (class);
++
++ object_class->finalize = flashback_workarounds_finalize;
++}
++
++static void
++flashback_workarounds_init (FlashbackWorkarounds *workarounds)
++{
++ FlashbackWorkaroundsPrivate *priv;
++
++ workarounds->priv = flashback_workarounds_get_instance_private (workarounds);
++ priv = workarounds->priv;
++
++ x11_init (workarounds);
++
++ workarounds->priv->g_settings = g_settings_new ("org.gnome.gnome-flashback.workarounds");
++ workarounds->priv->gtk_settings = gtk_settings_get_default ();
++
++ g_signal_connect (workarounds->priv->g_settings, "changed",
++ G_CALLBACK (g_settings_changed), workarounds);
++ g_signal_connect (workarounds->priv->gtk_settings, "notify::gtk-shell-shows-app-menu",
++ G_CALLBACK (gtk_settings_changed), workarounds);
++ g_signal_connect (workarounds->priv->gtk_settings, "notify::gtk-decoration-layout",
++ G_CALLBACK (gtk_settings_changed), workarounds);
++
++ add_workarounds (workarounds);
++}
++
++FlashbackWorkarounds *
++flashback_workarounds_new (void)
++{
++ return FLASHBACK_WORKAROUNDS (g_object_new (FLASHBACK_TYPE_WORKAROUNDS, NULL));
++}
+diff --git a/gnome-flashback/libworkarounds/flashback-workarounds.h b/gnome-flashback/libworkarounds/flashback-workarounds.h
+new file mode 100644
+index 0000000..328c38d
+--- /dev/null
++++ b/gnome-flashback/libworkarounds/flashback-workarounds.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (C) 2015 Alberts Muktupāvels
++ *
++ * 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 3 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/>.
++ */
++
++#ifndef FLASHBACK_WORKAROUNDS_H
++#define FLASHBACK_WORKAROUNDS_H
++
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define FLASHBACK_TYPE_WORKAROUNDS (flashback_workarounds_get_type ())
++#define FLASHBACK_WORKAROUNDS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FLASHBACK_TYPE_WORKAROUNDS, FlashbackWorkarounds))
++#define FLASHBACK_WORKAROUNDS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), FLASHBACK_TYPE_WORKAROUNDS, FlashbackWorkaroundsClass))
++#define FLASHBACK_IS_WORKAROUNDS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FLASHBACK_TYPE_WORKAROUNDS))
++#define FLASHBACK_IS_WORKAROUNDS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), FLASHBACK_TYPE_WORKAROUNDS))
++#define FLASHBACK_WORKAROUNDS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), FLASHBACK_TYPE_WORKAROUNDS, FlashbackWorkaroundsClass))
++
++typedef struct _FlashbackWorkarounds FlashbackWorkarounds;
++typedef struct _FlashbackWorkaroundsClass FlashbackWorkaroundsClass;
++typedef struct _FlashbackWorkaroundsPrivate FlashbackWorkaroundsPrivate;
++
++struct _FlashbackWorkarounds {
++ GObject parent;
++ FlashbackWorkaroundsPrivate *priv;
++};
++
++struct _FlashbackWorkaroundsClass {
++ GObjectClass parent_class;
++};
++
++GType flashback_workarounds_get_type (void);
++FlashbackWorkarounds *flashback_workarounds_new (void);
++
++G_END_DECLS
++
++#endif
+--
+2.1.0
+
diff --git a/gnome-flashback-wm-prefs-overrides.patch b/gnome-flashback-wm-prefs-overrides.patch
deleted file mode 100644
index 2da2633..0000000
--- a/gnome-flashback-wm-prefs-overrides.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in b/data/org.gnome.gnome-flashback.gschema.xml.in.in
-index 5c766a2..262409a 100644
---- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
-+++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
-@@ -41,4 +41,14 @@
- <_description>If set to true, then fade effect will be used to change the desktop background.</_description>
- </key>
- </schema>
-+
-+ <schema id="org.gnome.gnome-flashback.overrides" path="/org/gnome/gnome-flashback/overrides/">
-+ <key name="button-layout" type="s">
-+ <default>"appmenu:minimize,maximize,close"</default>
-+ <_summary>Arrangement of buttons on the titlebar</_summary>
-+ <_description>
-+ This key overrides the key in org.gnome.desktop.wm.preferences when running GNOME Flashback.
-+ </_description>
-+ </key>
-+ </schema>
- </schemalist>
diff --git a/gnome-flashback.spec b/gnome-flashback.spec
index 5305e14..dbf3562 100644
--- a/gnome-flashback.spec
+++ b/gnome-flashback.spec
@@ -1,12 +1,12 @@
Name: gnome-flashback
Version: 3.14.0
-Release: 4%{?dist}
+Release: 5%{?dist}
Summary: Classic GNOME session
License: GPLv3+
URL: https://wiki.gnome.org/Projects/GnomeFlashback
Source0: http://download.gnome.org/sources/%{name}/3.14/%{name}-%{version}.tar.xz
-Patch0: gnome-flashback-wm-prefs-overrides.patch
+Patch1: 0001-workarounds-add-app-menu-and-button-layout-workaroun.patch
BuildRequires: gnome-common
BuildRequires: gettext-devel
@@ -41,7 +41,8 @@ by integrating recent changes of the GNOME libraries.
%prep
%setup -q
-%patch0 -p1
+%patch1 -p1
+gnome-autogen.sh
%build
@@ -80,6 +81,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_datadir}/xsessions/gnome-flashback-metacity.desktop
%changelog
+* Sun Jul 12 2015 Yaakov Selkowitz <yselkowi@redhat.com> - 3.14.0-5
+- Backport upstream fix for BGO#738562
+
* Fri Feb 27 2015 Yaakov Selkowitz <yselkowi@redhat.com> - 3.14.0-4
- Fix for BGO#738562