diff -Nru gnome-control-center-3.6.3/configure.ac gnome-control-center-3.6.3/configure.ac --- gnome-control-center-3.6.3/configure.ac 2012-11-14 12:08:00.000000000 +0000 +++ gnome-control-center-3.6.3/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -19,6 +19,14 @@ LT_PREREQ([2.2]) LT_INIT +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + # Internationalization support IT_PROG_INTLTOOL([0.40.1]) @@ -94,7 +102,7 @@ dnl Check that we meet the dependencies dnl ============================================== -GLIB_REQUIRED_VERSION=2.31.0 +GLIB_REQUIRED_VERSION=2.31.2 GTK_REQUIRED_VERSION=3.5.13 PA_REQUIRED_VERSION=2.0 CANBERRA_REQUIRED_VERSION=0.13 @@ -104,7 +112,7 @@ NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 LIBNOTIFY_REQUIRED_VERSION=0.7.3 GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 -SCHEMAS_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.7.2.2 LIBWACOM_REQUIRED_VERSION=0.6 CLUTTER_REQUIRED_VERSION=1.11.3 GOA_REQUIRED_VERSION=3.5.90 @@ -127,8 +135,8 @@ gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) -PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) -PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0 x11) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION @@ -160,6 +168,8 @@ pwquality $SYSTEMD) +AM_PROG_VALAC([0.20.0]) + GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` AC_SUBST(GDESKTOP_PREFIX) @@ -295,7 +305,7 @@ PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" AC_SUBST(PANEL_CFLAGS) -PANEL_LIBS="" +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" AC_SUBST(PANEL_LIBS) PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" @@ -398,12 +408,13 @@ AC_OUTPUT([ Makefile +shell/libgnome-control-center.pc panels/Makefile panels/common/Makefile panels/background/Makefile panels/background/gnome-background-panel.desktop.in panels/bluetooth/Makefile -panels/bluetooth/bluetooth-properties.desktop.in +panels/bluetooth/gnome-bluetooth-panel.desktop.in panels/datetime/Makefile panels/datetime/gnome-datetime-panel.desktop.in panels/datetime/po-timezones/Makefile diff -Nru gnome-control-center-3.6.3/debian/bzr-builder.manifest gnome-control-center-3.6.3/debian/bzr-builder.manifest --- gnome-control-center-3.6.3/debian/bzr-builder.manifest 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/debian/bzr-builder.manifest 2015-02-22 15:27:37.000000000 +0000 @@ -0,0 +1,3 @@ +# bzr-builder format 0.3 deb-version {debversion}+elementary2 +lp:~elementary-os/ubuntu-package-imports/gnome-control-center-trusty revid:cody@elementaryos.org-20140711191130-88hmesgvs06maa4u +merge elementary-patch lp:~elementary-os/elementaryos/os-patch-gnome-control-center-trusty revid:cody@elementaryos.org-20150222152040-yao25tigtmmm6jal diff -Nru gnome-control-center-3.6.3/debian/changelog gnome-control-center-3.6.3/debian/changelog --- gnome-control-center-3.6.3/debian/changelog 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/changelog 2015-02-22 15:27:37.000000000 +0000 @@ -1,3 +1,18 @@ +gnome-control-center (1:3.6.3-0ubuntu56.1+elementary2~ubuntu14.04.1) trusty; urgency=low + + * Auto build. + + -- Launchpad Package Builder Sun, 22 Feb 2015 15:27:37 +0000 + +gnome-control-center (1:3.6.3-0ubuntu56.1) trusty; urgency=medium + + * debian/patches/ubuntu-gnome-version.patch: Merge build-time versioned + logo from unity-control-center (LP: #1299912) + * debian/rules: generate logo + * debian/control.in: build-depend on ubuntu font and valac + + -- Tim Lunn Mon, 05 May 2014 08:37:17 +1000 + gnome-control-center (1:3.6.3-0ubuntu56) trusty; urgency=medium * debian/patches/git_keyboard_grp_xkb_option.patch: diff -Nru gnome-control-center-3.6.3/debian/control gnome-control-center-3.6.3/debian/control --- gnome-control-center-3.6.3/debian/control 2014-04-10 15:25:38.000000000 +0000 +++ gnome-control-center-3.6.3/debian/control 2015-02-22 15:28:49.000000000 +0000 @@ -57,8 +57,10 @@ locales, network-manager-dev (>= 0.9) [linux-any], shared-mime-info, + ttf-ubuntu-font-family, libwebkitgtk-3.0-dev, libgl1-mesa-dev, + valac (>= 0.20.0), Vcs-Bzr: http://code.launchpad.net/~ubuntu-desktop/gnome-control-center/ubuntu Package: gnome-control-center diff -Nru gnome-control-center-3.6.3/debian/control.in gnome-control-center-3.6.3/debian/control.in --- gnome-control-center-3.6.3/debian/control.in 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/control.in 2015-02-22 15:27:24.000000000 +0000 @@ -53,8 +53,10 @@ locales, network-manager-dev (>= 0.9) [linux-any], shared-mime-info, + ttf-ubuntu-font-family, libwebkitgtk-3.0-dev, libgl1-mesa-dev, + valac (>= 0.20.0), Vcs-Bzr: http://code.launchpad.net/~ubuntu-desktop/gnome-control-center/ubuntu Package: gnome-control-center diff -Nru gnome-control-center-3.6.3/debian/gnome-control-center-data.install gnome-control-center-3.6.3/debian/gnome-control-center-data.install --- gnome-control-center-3.6.3/debian/gnome-control-center-data.install 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/gnome-control-center-data.install 2015-02-22 15:27:24.000000000 +0000 @@ -9,4 +9,3 @@ usr/share/polkit-1 #debian/gnome-control-center.pkla /var/lib/polkit-1/localauthority/10-vendor.d/ debian/source_gnome-control-center.py /usr/share/apport/package-hooks -debian/UbuntuLogo.png /usr/share/gnome-control-center/ui diff -Nru gnome-control-center-3.6.3/debian/gnome-control-center.sh gnome-control-center-3.6.3/debian/gnome-control-center.sh --- gnome-control-center-3.6.3/debian/gnome-control-center.sh 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/gnome-control-center.sh 2015-02-22 15:27:37.000000000 +0000 @@ -3,6 +3,8 @@ # Support legacy applications that still refer to gnome-control-center in Unity if [ "$XDG_CURRENT_DESKTOP" = "Unity" ] && [ -x /usr/bin/unity-control-center ]; then exec /usr/bin/unity-control-center $@ +elif [ "XDG_CURRENT_DESKTOP" = "Pantheon" ] && [ -x /usr/bin/switchboard ]; then + exec /usr/bin/switchboard $@ else exec /usr/bin/gnome-control-center.real $@ fi diff -Nru gnome-control-center-3.6.3/debian/patches/0001-online-accounts-use-the-async-function-to-get-all-th.patch gnome-control-center-3.6.3/debian/patches/0001-online-accounts-use-the-async-function-to-get-all-th.patch --- gnome-control-center-3.6.3/debian/patches/0001-online-accounts-use-the-async-function-to-get-all-th.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/0001-online-accounts-use-the-async-function-to-get-all-th.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -From 82e6777cb1a32edb9c85b85c0c3768f9ca62c4c2 Mon Sep 17 00:00:00 2001 -From: Marco Barisione -Date: Wed, 21 Aug 2013 11:48:25 +0100 -Subject: [PATCH] online-accounts: use the async function to get all the - providers - -https://bugzilla.gnome.org/show_bug.cgi?id=706148 ---- - panels/online-accounts/cc-online-accounts-panel.c | 49 ++++++++++++++++++----- - 1 file changed, 40 insertions(+), 9 deletions(-) - -Index: b/panels/online-accounts/cc-online-accounts-panel.c -=================================================================== ---- a/panels/online-accounts/cc-online-accounts-panel.c -+++ b/panels/online-accounts/cc-online-accounts-panel.c -@@ -596,9 +596,17 @@ - - /* ---------------------------------------------------------------------------------------------------- */ - -+typedef struct -+{ -+ GoaPanel *panel; -+} AddAccountData; -+ - static void --add_account (GoaPanel *panel) -+get_all_providers_cb (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data) - { -+ AddAccountData *data = user_data; - GtkWindow *parent; - GtkWidget *dialog; - gint response; -@@ -609,12 +617,15 @@ - - providers = NULL; - -- parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); -+ providers = NULL; -+ if (!goa_provider_get_all_finish (&providers, res, NULL)) -+ goto out; -+ -+ parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (data->panel)))); - -- dialog = goa_panel_add_account_dialog_new (panel->client); -+ dialog = goa_panel_add_account_dialog_new (data->panel->client); - gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); - -- providers = goa_provider_get_all (); - for (l = providers; l != NULL; l = l->next) - { - GoaProvider *provider; -@@ -643,11 +654,11 @@ - { - GtkTreeIter iter; - /* navigate to newly created object */ -- if (goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, -+ if (goa_panel_accounts_model_get_iter_for_object (data->panel->accounts_model, - object, - &iter)) - { -- gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), -+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->panel->accounts_treeview)), - &iter); - } - g_object_unref (object); -@@ -675,6 +686,18 @@ - out: - g_list_foreach (providers, (GFunc) g_object_unref, NULL); - g_list_free (providers); -+ g_clear_object (&data->panel); -+ g_slice_free (AddAccountData, data); -+} -+ -+static void -+add_account (GoaPanel *panel) -+{ -+ AddAccountData *data; -+ -+ data = g_slice_new0 (AddAccountData); -+ data->panel = g_object_ref_sink (panel); -+ goa_provider_get_all (get_all_providers_cb, data); - } - - /* ---------------------------------------------------------------------------------------------------- */ diff -Nru gnome-control-center-3.6.3/debian/patches/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch gnome-control-center-3.6.3/debian/patches/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch --- gnome-control-center-3.6.3/debian/patches/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -From 90f49a4d5dd646b8fce10f61a9231db4973a907b Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Thu, 16 May 2013 15:41:17 +0200 -Subject: [PATCH] rfkill-glib: Don't use g_assert_not_reached in type_to_string - -New kernel versions can add new RFKILL types, we should now crash here, -just say that we don't know what the switch is. ---- - panels/network/rfkill-glib.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/panels/network/rfkill-glib.c b/panels/network/rfkill-glib.c -index e27ca40..7c9ee3c 100644 ---- a/panels/network/rfkill-glib.c -+++ b/panels/network/rfkill-glib.c -@@ -80,7 +80,7 @@ type_to_string (unsigned int type) - case RFKILL_TYPE_WWAN: - return "WWAN"; - default: -- g_assert_not_reached (); -+ return "UNKNOWN"; - } - } - --- -1.8.3.2 - diff -Nru gnome-control-center-3.6.3/debian/patches/05_run_update_manager.patch gnome-control-center-3.6.3/debian/patches/05_run_update_manager.patch --- gnome-control-center-3.6.3/debian/patches/05_run_update_manager.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/05_run_update_manager.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Index: b/panels/info/cc-info-panel.c -=================================================================== ---- a/panels/info/cc-info-panel.c -+++ b/panels/info/cc-info-panel.c -@@ -1900,7 +1900,7 @@ - { - GError *error; - error = NULL; -- g_spawn_command_line_async ("gpk-update-viewer", &error); -+ g_spawn_command_line_async ("update-manager", &error); - if (error != NULL) - { - g_warning ("unable to launch Software Updates: %s", error->message); diff -Nru gnome-control-center-3.6.3/debian/patches/06_handle_passwd_with_ldap.patch gnome-control-center-3.6.3/debian/patches/06_handle_passwd_with_ldap.patch --- gnome-control-center-3.6.3/debian/patches/06_handle_passwd_with_ldap.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/06_handle_passwd_with_ldap.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Description: Handle the case where passwd re-asks for the current password when it was entered incorrectly (when using LDAP) - Based on a patch from Ryan Tandy -Author: Chris Coulson -Bug-Ubuntu: https:/launchpad.net/bugs/607357 -Forwarded: no - -Index: b/panels/user-accounts/run-passwd.c -=================================================================== ---- a/panels/user-accounts/run-passwd.c -+++ b/panels/user-accounts/run-passwd.c -@@ -408,7 +408,7 @@ - - if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) { - -- if (strstr (str->str, "assword: ") != NULL) { -+ if (strstr (str->str, "assword: ") != NULL && strstr (str->str, "incorrect") == NULL) { - /* Authentication successful */ - - passwd_handler->backend_state = PASSWD_STATE_NEW; diff -Nru gnome-control-center-3.6.3/debian/patches/11_power-configure_lid_action.patch gnome-control-center-3.6.3/debian/patches/11_power-configure_lid_action.patch --- gnome-control-center-3.6.3/debian/patches/11_power-configure_lid_action.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/11_power-configure_lid_action.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -Subject: [PATCH] power: Add configuration for lid action -Bug: https://bugzilla.gnome.org/show_bug.cgi?id=659045 -Bug-Ubuntu: https://bugs.launchpad.net/bugs/792636 ---- a/panels/power/cc-power-panel.c -+++ b/panels/power/cc-power-panel.c -@@ -932,6 +932,7 @@ - set_ac_battery_ui_mode (CcPowerPanel *self) - { - gboolean has_batteries = FALSE; -+ gboolean has_lid = FALSE; - gboolean ret; - GError *error = NULL; - GPtrArray *devices; -@@ -964,7 +965,13 @@ - } - } - g_ptr_array_unref (devices); -+ -+ has_lid = up_client_get_lid_is_present (self->priv->up_client); -+ - out: -+ gtk_widget_set_visible (WID (priv->builder, "combobox_lid_ac"), has_lid); -+ gtk_widget_set_visible (WID (priv->builder, "label_lid_action"), has_lid); -+ gtk_widget_set_visible (WID (priv->builder, "combobox_lid_battery"), has_batteries && has_lid); - gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); - gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); - gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); -@@ -1080,6 +1087,26 @@ - G_CALLBACK (activate_link_cb), - self); - -+ value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-ac-action"); -+ widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, -+ "combobox_lid_ac")); -+ disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); -+ set_value_for_combo (GTK_COMBO_BOX (widget), value); -+ g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-ac-action"); -+ g_signal_connect (widget, "changed", -+ G_CALLBACK (combo_enum_changed_cb), -+ self); -+ -+ value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-battery-action"); -+ widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, -+ "combobox_lid_battery")); -+ disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); -+ set_value_for_combo (GTK_COMBO_BOX (widget), value); -+ g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-battery-action"); -+ g_signal_connect (widget, "changed", -+ G_CALLBACK (combo_enum_changed_cb), -+ self); -+ - widget = WID (self->priv->builder, "vbox_power"); - gtk_widget_reparent (widget, (GtkWidget *) self); - } ---- a/panels/power/power.ui -+++ b/panels/power/power.ui -@@ -53,6 +53,28 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Suspend -+ 1 -+ True -+ -+ -+ Do nothing -+ 5 -+ True -+ -+ -+ - - False - False -@@ -172,6 +194,50 @@ - 2 - - -+ -+ -+ True -+ False -+ end -+ When the lid is closed -+ -+ -+ 0 -+ 3 -+ -+ -+ -+ -+ True -+ False -+ liststore_lid -+ True -+ -+ -+ -+ -+ -+ -+ 1 -+ 3 -+ -+ -+ -+ -+ True -+ False -+ liststore_lid -+ True -+ -+ -+ -+ -+ -+ -+ 2 -+ 3 -+ -+ - - - False -@@ -352,9 +418,12 @@ - - - -+ -+ - - - -+ - - - diff -Nru gnome-control-center-3.6.3/debian/patches/12_add_never_turn_screen_off.patch gnome-control-center-3.6.3/debian/patches/12_add_never_turn_screen_off.patch --- gnome-control-center-3.6.3/debian/patches/12_add_never_turn_screen_off.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/12_add_never_turn_screen_off.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -Index: b/panels/screen/cc-screen-panel.c -=================================================================== ---- a/panels/screen/cc-screen-panel.c -+++ b/panels/screen/cc-screen-panel.c -@@ -402,8 +402,7 @@ - gtk_tree_model_get (model, &iter, - 1, &value_tmp, - -1); -- if (value == value_tmp || -- (value_tmp > value_prev && value < value_tmp)) -+ if (value == value_tmp) - { - gtk_combo_box_set_active_iter (combo_box, &iter); - return; -Index: b/panels/screen/screen.ui -=================================================================== ---- a/panels/screen/screen.ui -+++ b/panels/screen/screen.ui -@@ -84,6 +84,10 @@ - 1 hour - 3600 - -+ -+ Never -+ 0 -+ - - - diff -Nru gnome-control-center-3.6.3/debian/patches/51_unity_options_in_display_panel.patch gnome-control-center-3.6.3/debian/patches/51_unity_options_in_display_panel.patch --- gnome-control-center-3.6.3/debian/patches/51_unity_options_in_display_panel.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/51_unity_options_in_display_panel.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,592 +0,0 @@ -Index: gnome-control-center-3.4.2/panels/display/cc-display-panel.c -=================================================================== ---- gnome-control-center-3.4.2.orig/panels/display/cc-display-panel.c 2012-05-15 12:18:30.000000000 +0200 -+++ gnome-control-center-3.4.2/panels/display/cc-display-panel.c 2012-07-23 10:26:57.281976435 +0200 -@@ -54,6 +54,13 @@ - #define MINIMUM_WIDTH 675 - #define MINIMUM_HEIGHT 530 - -+#define UNITY_GSETTINGS_SCHEMA "org.compiz.unityshell" -+#define UNITY_GSETTINGS_PATH "/org/compiz/profiles/unity/plugins/unityshell/" -+#define UNITY_LAUNCHER_ALL_MONITORS_KEY "num-launchers" -+#define UNITY_STICKY_EDGE_KEY "launcher-capture-mouse" -+#define UNITY2D_GSETTINGS_MAIN "com.canonical.Unity2d" -+#define UNITY2D_GSETTINGS_LAUNCHER "com.canonical.Unity2d.Launcher" -+ - enum { - TEXT_COL, - WIDTH_COL, -@@ -72,6 +79,9 @@ - GnomeRROutputInfo *current_output; - - GSettings *clock_settings; -+ GSettings *unity_settings; -+ GSettings *unity2d_settings_main; -+ GSettings *unity2d_settings_launcher; - GtkBuilder *builder; - guint focus_id; - -@@ -119,6 +129,8 @@ - guint n_properties, - GObjectConstructParam *properties); - static void on_screen_changed (GnomeRRScreen *scr, gpointer data); -+static void refresh_unity_launcher_placement (CcDisplayPanel *self); -+static gboolean unity_launcher_on_all_monitors (GSettings *settings); - - static void - cc_display_panel_get_property (GObject *object, -@@ -168,6 +180,13 @@ - if (self->priv->clock_settings != NULL) - g_object_unref (self->priv->clock_settings); - -+ if (self->priv->unity2d_settings_main != NULL) -+ g_object_unref (self->priv->unity2d_settings_main); -+ if (self->priv->unity2d_settings_launcher != NULL) -+ g_object_unref (self->priv->unity2d_settings_launcher); -+ if (self->priv->unity_settings != NULL) -+ g_object_unref (self->priv->unity_settings); -+ - shell = cc_panel_get_shell (CC_PANEL (self)); - if (shell != NULL) - { -@@ -223,6 +242,12 @@ - } - - static gboolean -+is_unity_session (void) -+{ -+ return (g_strcmp0 (g_getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0); -+} -+ -+static gboolean - should_show_resolution (gint output_width, - gint output_height, - gint width, -@@ -262,6 +287,9 @@ - gnome_rr_labeler_show (self->priv->labeler); - - select_current_output_from_dialog_position (self); -+ -+ if (is_unity_session ()) -+ refresh_unity_launcher_placement (self); - } - - static void -@@ -599,6 +627,10 @@ - gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); - gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); - -+ /* set inactive the launcher placement choice */ -+ gtk_widget_set_sensitive (WID ("launcher_placement_combo"), !mirror_is_active); -+ gtk_widget_set_sensitive (WID ("stickyedge_switch"), !mirror_is_active); -+ - g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); - } - -@@ -838,6 +870,7 @@ - rebuild_on_off_radios (self); - rebuild_resolution_combo (self); - rebuild_rotation_combo (self); -+ refresh_unity_launcher_placement (self); - - self->priv->ignore_gui_changes = FALSE; - } -@@ -1722,6 +1755,10 @@ - outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); - for (i = 0; outputs[i] != NULL; ++i) - gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); -+ -+ gtk_widget_queue_draw (WID ("self->priv->area")); -+ /* refresh the combobox */ -+ refresh_unity_launcher_placement (self); - } - - static void -@@ -2073,7 +2110,30 @@ - g_object_unref (layout); - cairo_restore (cr); - -- if (gnome_rr_output_info_get_primary (output)) -+ /* Only display a launcher on all or primary monitor */ -+ if (is_unity_session ()) -+ { -+ if (gnome_rr_output_info_is_active (output) && (unity_launcher_on_all_monitors (self->priv->unity_settings) || gnome_rr_output_info_get_primary (output))) -+ { -+ cairo_rectangle (cr, x, y, 10, h * scale + 0.5); -+ cairo_set_source_rgb (cr, 0, 0, 0); -+ foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), -+ cr, -+ (FooScrollAreaEventFunc) on_top_bar_event, -+ self); -+ cairo_fill (cr); -+ -+ cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); -+ cairo_rectangle (cr, x + 1, y + 6, 8, 8); -+ cairo_rectangle (cr, x + 1, y + 16, 8, 8); -+ cairo_rectangle (cr, x + 1, y + 26, 8, 8); -+ cairo_rectangle (cr, x + 1, y + 36, 8, 8); -+ cairo_rectangle (cr, x + 1, y + h * scale + 0.5 - 10, 8, 8); -+ cairo_fill (cr); -+ } -+ } -+ -+ if (gnome_rr_output_info_get_primary (output) && !is_unity_session ()) - { - const char *clock_format; - char *text; -@@ -2556,6 +2616,233 @@ - } - - static void -+stickyedge_widget_refresh (GtkSwitch *switcher, GSettings *settings) -+{ -+ gboolean stickyedge_enabled = g_settings_get_boolean (settings, UNITY_STICKY_EDGE_KEY); -+ -+ gtk_switch_set_active (switcher, stickyedge_enabled); -+} -+ -+static void -+ext_stickyedge_changed_callback (GSettings* settings, -+ guint key, -+ gpointer user_data) -+{ -+ stickyedge_widget_refresh (GTK_SWITCH (user_data), settings); -+} -+ -+static void -+on_stickyedge_changed (GtkSwitch *switcher, GParamSpec *pspec, gpointer user_data) -+{ -+ CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); -+ gboolean enabled = gtk_switch_get_active (GTK_SWITCH (switcher)); -+ -+ /* 3d */ -+ g_settings_set_boolean (self->priv->unity_settings, UNITY_STICKY_EDGE_KEY, enabled); -+ /* 2d */ -+ if (self->priv->unity2d_settings_main) -+ g_settings_set_boolean (self->priv->unity2d_settings_main, "sticky-edges", enabled); -+} -+ -+static gboolean -+unity_launcher_on_all_monitors (GSettings *settings) -+{ -+ gint value = g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY); -+ return (value == 0); -+} -+ -+static GdkPixbuf* -+get_monitor_pixbuf (CcDisplayPanel *self, GnomeRROutputInfo *output) -+{ -+ GdkRGBA color; -+ cairo_surface_t *cairo_surface; -+ cairo_t *cr; -+ int monitor_width = 30; -+ int monitor_height = 15; -+ -+ gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); -+ -+ cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); -+ cr = cairo_create (cairo_surface); -+ cairo_surface_destroy (cairo_surface); -+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); -+ cairo_paint (cr); -+ -+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER); -+ cairo_set_source_rgb (cr, color.red, color.green, color.blue); -+ cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); -+ cairo_fill (cr); -+ -+ cairo_set_line_width (cr, 1); -+ cairo_set_source_rgba (cr, 0, 0, 0, 1.0); -+ cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); -+ cairo_stroke (cr); -+ -+ return gdk_pixbuf_get_from_surface (cairo_get_target (cr), 0, 0, monitor_width, monitor_height); -+} -+ -+static void -+refresh_unity_launcher_placement (CcDisplayPanel *self) -+{ -+ GtkWidget *launcher_placement_combo = WID ("launcher_placement_combo"); -+ GtkListStore *liststore; -+ GtkTreeIter iter; -+ GList *connected_outputs = NULL; -+ GList *list; -+ gboolean launcher_on_all_monitors = unity_launcher_on_all_monitors (self->priv->unity_settings); -+ gint index_of_primary_screen = 0; -+ gint i; -+ -+ liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "available_launcher_placement_store"); -+ gtk_list_store_clear (liststore); -+ -+ connected_outputs = list_connected_outputs (self, NULL, NULL); -+ for (list = connected_outputs, i = 0; list != NULL; list = list->next) -+ { -+ char *monitor_name; -+ GdkPixbuf *monitor_pixbuf; -+ GnomeRROutputInfo *output = list->data; -+ -+ if (!gnome_rr_output_info_is_active (output)) -+ continue; -+ -+ gtk_list_store_append (liststore, &iter); -+ monitor_name = g_strdup (gnome_rr_output_info_get_display_name (output)); -+ monitor_pixbuf = get_monitor_pixbuf (self, output); -+ -+ gtk_list_store_set (liststore, &iter, 0, monitor_pixbuf, 1, monitor_name, -1); -+ -+ /* select it if primary and only one launcher */ -+ if (gnome_rr_output_info_get_primary (output) && (!launcher_on_all_monitors)) -+ index_of_primary_screen = i; -+ i++; -+ -+ g_object_unref (monitor_pixbuf); -+ g_free (monitor_name); -+ } -+ -+ // FIXME: check autosort? -+ gtk_list_store_append (liststore, &iter); -+ gtk_list_store_set (liststore, &iter, 0, NULL, 1, _("All displays"), -1); -+ -+ if (launcher_on_all_monitors) -+ index_of_primary_screen = i; -+ -+ gtk_combo_box_set_active (GTK_COMBO_BOX (launcher_placement_combo), index_of_primary_screen); -+} -+ -+static gboolean -+switcher_set_to_launcher_on_all_monitors (CcDisplayPanel *self) -+{ -+ GtkComboBox *combo = GTK_COMBO_BOX (WID ("launcher_placement_combo")); -+ gint active = gtk_combo_box_get_active (combo); -+ gint number_items = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), -+ NULL); -+ return (active == number_items - 1); -+} -+ -+static void -+ext_launcher_placement_changed_callback (GSettings* settings, -+ guint key, -+ gpointer user_data) -+{ -+ // add some crazyness as 2d/3d are not using the same keys -+ CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); -+ gint launcher_unity_value = 0; -+ -+ // two options support: all monitors (0)i or just primary desktop (hence set to 1, not any other number) -+ if (! switcher_set_to_launcher_on_all_monitors (self)) -+ launcher_unity_value = 1; -+ -+ if (g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY) != launcher_unity_value) -+ refresh_unity_launcher_placement (self); -+} -+ -+static void -+on_launcher_placement_combo_changed (GtkComboBox *combo, CcDisplayPanel *self) -+{ -+ gint active = gtk_combo_box_get_active (combo); -+ gint i; -+ gint index_on_combo = 0; -+ -+ if (active < 0) -+ return; -+ gint value = 0; -+ gboolean on_all_monitors = switcher_set_to_launcher_on_all_monitors (self); -+ -+ if (!on_all_monitors) { -+ value = 1; -+ // set the primary output if needed -+ GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); -+ -+ for (i = 0; outputs[i] != NULL; ++i) -+ { -+ GnomeRROutputInfo *output = outputs[i]; -+ if (!gnome_rr_output_info_is_active (output)) -+ continue; -+ -+ if ((active == index_on_combo) && !gnome_rr_output_info_get_primary (output)) -+ { -+ set_primary_output (self, output); -+ break; -+ } -+ index_on_combo++; -+ } -+ } -+ -+ /* 3d */ -+ if (self->priv->unity_settings) -+ g_settings_set_int (self->priv->unity_settings, UNITY_LAUNCHER_ALL_MONITORS_KEY, value); -+ /* 2d */ -+ if (self->priv->unity2d_settings_launcher) -+ g_settings_set_boolean (self->priv->unity2d_settings_launcher, "only-one-launcher", !on_all_monitors); -+} -+ -+static void -+setup_unity_settings (CcDisplayPanel *self) -+{ -+ const gchar * const *schemas; -+ -+ /* Only use the unity-2d schema if it's installed */ -+ schemas = g_settings_list_schemas (); -+ while (*schemas != NULL) -+ { -+ if (g_strcmp0 (*schemas, UNITY2D_GSETTINGS_LAUNCHER) == 0) -+ { -+ self->priv->unity2d_settings_main = g_settings_new (UNITY2D_GSETTINGS_MAIN); -+ self->priv->unity2d_settings_launcher = g_settings_new (UNITY2D_GSETTINGS_LAUNCHER); -+ break; -+ } -+ schemas++; -+ } -+ schemas = g_settings_list_relocatable_schemas (); -+ while (*schemas != NULL) -+ { -+ if (g_strcmp0 (*schemas, UNITY_GSETTINGS_SCHEMA) == 0) -+ { -+ self->priv->unity_settings = g_settings_new_with_path (UNITY_GSETTINGS_SCHEMA, UNITY_GSETTINGS_PATH); -+ break; -+ } -+ schemas++; -+ } -+ -+ if (!self->priv->unity_settings) -+ return; -+ -+ GtkWidget *sticky_edge_switch = WID ("stickyedge_switch"); -+ g_signal_connect (sticky_edge_switch, "notify::active", -+ G_CALLBACK (on_stickyedge_changed), self); -+ g_signal_connect (self->priv->unity_settings, "changed::" UNITY_STICKY_EDGE_KEY, -+ G_CALLBACK (ext_stickyedge_changed_callback), sticky_edge_switch); -+ stickyedge_widget_refresh (GTK_SWITCH (sticky_edge_switch), self->priv->unity_settings); -+ -+ g_signal_connect (G_OBJECT (WID ("launcher_placement_combo")), "changed", -+ G_CALLBACK (on_launcher_placement_combo_changed), self); -+ g_signal_connect (self->priv->unity_settings, "changed::" UNITY_LAUNCHER_ALL_MONITORS_KEY, -+ G_CALLBACK (ext_launcher_placement_changed_callback), self); -+} -+ -+static void - cc_display_panel_init (CcDisplayPanel *self) - { - } -@@ -2572,7 +2859,7 @@ - CcDisplayPanel *self; - CcShell *shell; - GtkWidget *toplevel; -- gchar *objects[] = {"display-panel", NULL}; -+ gchar *objects[] = {"display-panel", "available_launcher_placement_store", NULL}; - - obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); - self = CC_DISPLAY_PANEL (obj); -@@ -2661,6 +2948,18 @@ - g_signal_connect_swapped (WID ("apply_button"), - "clicked", G_CALLBACK (apply), self); - -+ /* Unity settings */ -+ if (is_unity_session ()) -+ setup_unity_settings (self); -+ else -+ { -+ gtk_widget_hide (WID ("unity_launcher_placement_sep")); -+ gtk_widget_hide (WID ("launcher_placement_label")); -+ gtk_widget_hide (WID ("sticky_edge_label")); -+ gtk_widget_hide (WID ("launcher_placement_combo")); -+ gtk_widget_hide (WID ("stickyedge_switch")); -+ } -+ - gtk_widget_show (self->priv->panel); - gtk_container_add (GTK_CONTAINER (self), self->priv->panel); - -@@ -2675,4 +2974,3 @@ - CC_TYPE_DISPLAY_PANEL, - "display", 0); - } -- -Index: gnome-control-center-3.4.2/panels/display/display-capplet.ui -=================================================================== ---- gnome-control-center-3.4.2.orig/panels/display/display-capplet.ui 2012-03-05 15:04:55.000000000 +0100 -+++ gnome-control-center-3.4.2/panels/display/display-capplet.ui 2012-07-23 10:26:45.805976846 +0200 -@@ -1,6 +1,14 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -96,56 +104,89 @@ - - - True -- 3 -+ 5 - 2 - 12 - 6 - -- -+ -+ True -+ 1 -+ _Resolution -+ True -+ resolution_combo -+ -+ -+ -+ GTK_FILL -+ -+ -+ -+ -+ -+ True -+ 1 -+ R_otation -+ rotation_combo -+ True -+ -+ -+ -+ 1 -+ 2 -+ GTK_FILL -+ -+ -+ -+ -+ - True -- -- -- - - -- 1 -- 2 - 2 - 3 -- -+ 0 -+ 2 -+ GTK_FILL - - - - -- -+ - True - 1 -- _Resolution -+ L_auncher placement -+ launcher_placement_combo - True -- resolution_combo - - - -+ 3 -+ 4 - GTK_FILL - - - - -- -+ - True - 1 -- R_otation -- rotation_combo -+ S_ticky edges -+ stickyedge_switch - True - - - -- 1 -- 2 -+ 4 -+ 5 - GTK_FILL - - -@@ -179,6 +220,63 @@ - - - -+ -+ True -+ False -+ available_launcher_placement_store -+ 1 -+ -+ -+ -+ 0 -+ -+ -+ -+ -+ -+ 1 -+ -+ -+ -+ -+ 1 -+ 2 -+ 3 -+ 4 -+ -+ -+ -+ -+ -+ True -+ 12 -+ -+ -+ True -+ True -+ False -+ True -+ -+ -+ False -+ False -+ end -+ 1 -+ -+ -+ -+ -+ 1 -+ 2 -+ 4 -+ 5 -+ -+ False -+ False -+ 0 -+ -+ -+ - - - diff -Nru gnome-control-center-3.6.3/debian/patches/52_region_language.patch gnome-control-center-3.6.3/debian/patches/52_region_language.patch --- gnome-control-center-3.6.3/debian/patches/52_region_language.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/52_region_language.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,652 +0,0 @@ -Description: Adapts the region capplet and the language chooser in the user accounts capplet -Forwarded: https://bugzilla.gnome.org/695939, https://bugzilla.gnome.org/695940 -Author: Gunnar Hjalmarsson -Last-Update: 2013-03-21 - - Some background that explains the need for this patch: - - * Ubuntu isn't shipped with all languages installed and all locales generated. - Instead the users install the needed language pack(s), and the corresponding - locales are generated. - - * The code in accountsservice for handling languages has been extended via Ubuntu - specific patches. That code is shared by multiple packages. Currently those - packages are: - - gnome-control-center - - language-selector (Xubuntu and Lubuntu will keep using the language-selector - UI for now) - - lightdm (for the language chooser in lightdm-gtk-greeter) - - With this patch applied, the g-c-c region capplet and the language chooser in the - user accounts capplet behave approximately the same way as language-selector. No - migration code needed when standard Ubuntu drops the language-selector UI. - - Compared with how the region capplet in g-c-c works out of the box, this patch - results in: - - * Languages are dealt with using 'll' and 'll_CC' language codes instead of - complete locale names. - - * Selected language is stored in both LANGUAGE and LANG. - - * Only one language list that shows the translations belonging to the installed - language packs (not a 'short' and a 'long' list). - - * User level settings of language and regional formats are stored as - accountsservice properties and in ~/.pam_environment. - - * All the formats related locale categories set, not just a subset. - - * Translation @variants, e.g. ca@valencia, are displayed properly. - - * Locales stored with codeset '.UTF-8' instead of '.utf8'. - - * The 'common_name' field taken into account when parsing the iso-codes XML files - for language names. - -Index: gnome-control-center-3.6.3/panels/common/cc-common-language.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/common/cc-common-language.c 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/common/cc-common-language.c 2013-03-21 14:22:09.358586554 +0100 -@@ -326,6 +326,66 @@ - return language; - } - -+gchar * -+cc_common_language_get_property (const gchar *prop_name) -+{ -+ GDBusConnection *bus; -+ gchar *user_path; -+ GError *error = NULL; -+ GVariant *properties; -+ GVariantIter *iter; -+ gchar *key; -+ GVariant *value; -+ gchar *ret = NULL; -+ -+ if (g_strcmp0 (prop_name, "Language") != 0 && g_strcmp0 (prop_name, "FormatsLocale") != 0) { -+ g_warning ("Invalid argument: '%s'", prop_name); -+ return ret; -+ } -+ -+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); -+ user_path = g_strdup_printf ("/org/freedesktop/Accounts/User%i", getuid ()); -+ -+ properties = g_dbus_connection_call_sync (bus, -+ "org.freedesktop.Accounts", -+ user_path, -+ "org.freedesktop.DBus.Properties", -+ "GetAll", -+ g_variant_new ("(s)", "org.freedesktop.Accounts.User"), -+ G_VARIANT_TYPE ("(a{sv})"), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, -+ &error); -+ if (!properties) { -+ g_warning ("Error calling GetAll() when retrieving properties for %s: %s", user_path, error->message); -+ g_error_free (error); -+ /* g_hash_table_lookup() is not NULL-safe, so don't return NULL */ -+ if (g_strcmp0 (prop_name, "Language") == 0) -+ ret = g_strdup ("en"); -+ else -+ ret = g_strdup ("en_US.UTF-8"); -+ goto out; -+ } -+ -+ g_variant_get (properties, "(a{sv})", &iter); -+ while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { -+ if (g_strcmp0 (key, prop_name) == 0) { -+ g_variant_get (value, "s", &ret); -+ break; -+ } -+ } -+ -+ g_variant_unref (properties); -+ g_variant_iter_free (iter); -+ -+out: -+ g_object_unref (bus); -+ g_free (user_path); -+ -+ return ret; -+} -+ - static void - languages_foreach_cb (gpointer key, - gpointer value, -@@ -407,7 +467,7 @@ - char *lang; - gboolean found; - -- lang = cc_common_language_get_current_language (); -+ lang = cc_common_language_get_property ("Language"); - g_debug ("Trying to select lang '%s' in treeview", lang); - model = gtk_tree_view_get_model (treeview); - found = FALSE; -@@ -440,6 +500,7 @@ - g_warning ("Could not find current language '%s' in the treeview", lang); - } - -+/* - static void - add_other_users_language (GHashTable *ht) - { -@@ -519,6 +580,7 @@ - - g_object_unref (proxy); - } -+*/ - - GHashTable * - cc_common_language_get_initial_languages (void) -@@ -530,6 +592,7 @@ - ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - /* Add some common languages first */ -+/* - g_hash_table_insert (ht, g_strdup ("en_US.utf8"), g_strdup (_("English"))); - if (gdm_language_has_translations ("en_GB")) - g_hash_table_insert (ht, g_strdup ("en_GB.utf8"), g_strdup (_("British English"))); -@@ -550,12 +613,29 @@ - if (gdm_language_has_translations ("ar") || - gdm_language_has_translations ("ar_EG")) - g_hash_table_insert (ht, g_strdup ("ar_EG.utf8"), g_strdup (_("Arabic"))); -- -+*/ - /* Add the languages used by other users on the system */ -- add_other_users_language (ht); -+// add_other_users_language (ht); -+ -+ /* Add installed languages */ -+ gchar *avail_languages; -+ GError *error = NULL; -+ if (g_spawn_command_line_sync ("/usr/share/language-tools/language-options", -+ &avail_languages, NULL, NULL, &error)) { -+ name = strtok (avail_languages, "\n"); -+ while (name != NULL) { -+ language = gdm_get_language_from_name (name, NULL); -+ g_hash_table_insert (ht, g_strdup (name), language); -+ name = strtok (NULL, "\n"); -+ } -+ g_free (avail_languages); -+ } else { -+ g_warning ("Couldn't get available languages: %s", error->message); -+ g_error_free (error); -+ } - -- /* Add current locale */ -- name = cc_common_language_get_current_language (); -+ /* Add current language */ -+ name = cc_common_language_get_property ("Language"); - if (g_hash_table_lookup (ht, name) == NULL) { - language = gdm_get_language_from_name (name, NULL); - g_hash_table_insert (ht, name, language); -Index: gnome-control-center-3.6.3/panels/common/cc-common-language.h -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/common/cc-common-language.h 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/common/cc-common-language.h 2013-03-15 17:20:48.903849975 +0100 -@@ -45,6 +45,7 @@ - GHashTable *user_langs); - gboolean cc_common_language_has_font (const gchar *locale); - gchar *cc_common_language_get_current_language (void); -+gchar *cc_common_language_get_property (const gchar *prop_name); - - GHashTable *cc_common_language_get_initial_languages (void); - GHashTable *cc_common_language_get_initial_regions (const gchar *lang); -Index: gnome-control-center-3.6.3/panels/common/cc-language-chooser.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/common/cc-language-chooser.c 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/common/cc-language-chooser.c 2013-03-15 17:20:48.919849976 +0100 -@@ -105,8 +105,8 @@ - - user_langs = cc_common_language_get_initial_languages (); - -- /* Add the current locale first */ -- name = cc_common_language_get_current_language (); -+ /* Add the current language first */ -+ name = cc_common_language_get_property ("Language"); - display = g_hash_table_lookup (user_langs, name); - - gtk_list_store_append (store, &iter); -@@ -118,8 +118,8 @@ - g_hash_table_foreach (user_langs, (GHFunc) languages_foreach_cb, store); - - /* And now the "Other..." selection */ -- gtk_list_store_append (store, &iter); -- gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1); -+// gtk_list_store_append (store, &iter); -+// gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1); - - g_hash_table_destroy (user_langs); - } -Index: gnome-control-center-3.6.3/panels/common/gdm-languages.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/common/gdm-languages.c 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/common/gdm-languages.c 2013-03-15 17:20:48.923849976 +0100 -@@ -224,6 +224,7 @@ - const char *codeset, - const char *modifier) - { -+ const char *adj_codeset; - char *name; - - g_assert (language[0] != 0); -@@ -231,12 +232,17 @@ - g_assert (codeset == NULL || codeset[0] != 0); - g_assert (modifier == NULL || modifier[0] != 0); - -+ if (g_strcmp0 (codeset, "utf8") == 0) { -+ adj_codeset = "UTF-8"; -+ } else -+ adj_codeset = codeset; -+ - name = g_strdup_printf ("%s%s%s%s%s%s%s", - language, - territory != NULL? "_" : "", - territory != NULL? territory : "", - codeset != NULL? "." : "", -- codeset != NULL? codeset : "", -+ codeset != NULL? adj_codeset : "", - modifier != NULL? "@" : "", - modifier != NULL? modifier : ""); - -@@ -854,6 +860,7 @@ - const char *ccode_longT; - const char *ccode; - const char *ccode_id; -+ const char *lang_common_name; - const char *lang_name; - - if (! (g_str_equal (element_name, "iso_639_entry") || g_str_equal (element_name, "iso_639_3_entry")) -@@ -865,6 +872,7 @@ - ccode_longB = NULL; - ccode_longT = NULL; - ccode_id = NULL; -+ lang_common_name = NULL; - lang_name = NULL; - - while (*attr_names && *attr_values) { -@@ -901,6 +909,11 @@ - } - ccode_id = *attr_values; - } -+ } else if (g_str_equal (*attr_names, "common_name")) { -+ /* skip if empty */ -+ if (**attr_values) { -+ lang_common_name = *attr_values; -+ } - } else if (g_str_equal (*attr_names, "name")) { - lang_name = *attr_values; - } -@@ -909,6 +922,10 @@ - ++attr_values; - } - -+ if (lang_common_name != NULL) { -+ lang_name = lang_common_name; -+ } -+ - if (lang_name == NULL) { - return; - } -@@ -1131,6 +1148,7 @@ - char *langinfo_codeset; - char *translated_language; - char *translated_territory; -+ char *modifier; - gboolean is_utf8 = TRUE; - - g_return_val_if_fail (name != NULL, NULL); -@@ -1153,12 +1171,13 @@ - language_code = NULL; - territory_code = NULL; - codeset_code = NULL; -+ modifier = NULL; - - gdm_parse_language_name (name, - &language_code, - &territory_code, - &codeset_code, -- NULL); -+ &modifier); - - if (language_code == NULL) { - goto out; -@@ -1184,7 +1203,7 @@ - translated_territory); - } - -- language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); -+// language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); - - if (codeset_code == NULL && langinfo_codeset != NULL) { - codeset_code = g_strdup (langinfo_codeset); -@@ -1196,6 +1215,10 @@ - codeset_code); - } - -+ if (modifier != NULL) { -+ g_string_append_printf (full_language, " - %s", modifier); -+ } -+ - out: - g_free (language_code); - g_free (territory_code); -@@ -1203,6 +1226,7 @@ - g_free (langinfo_codeset); - g_free (translated_language); - g_free (translated_territory); -+ g_free (modifier); - - if (full_language->len == 0) { - g_string_free (full_language, TRUE); -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-formats.c 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c 2013-03-15 17:20:48.927849976 +0100 -@@ -31,6 +31,7 @@ - #include "cc-language-chooser.h" - #include "gdm-languages.h" - #include "gnome-region-panel-formats.h" -+#include "gnome-region-panel-system.h" - - static void - display_date (GtkLabel *label, GDateTime *dt, const gchar *format) -@@ -149,6 +150,46 @@ - g_free (active_id); - } - -+static void -+set_formats_locale (const gchar *formats_locale) -+{ -+ GDBusProxy *proxy; -+ GError *error = NULL; -+ gchar *user_path; -+ GVariant *ret; -+ -+ user_path = g_strdup_printf ("/org/freedesktop/Accounts/User%i", getuid ()); -+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, -+ G_DBUS_PROXY_FLAGS_NONE, -+ NULL, -+ "org.freedesktop.Accounts", -+ user_path, -+ "org.freedesktop.Accounts.User", -+ NULL, -+ &error); -+ if (!proxy) { -+ g_warning ("Couldn't get accountsservice proxy for %s: %s", user_path, error->message); -+ g_error_free (error); -+ g_free (user_path); -+ return; -+ } -+ -+ ret = g_dbus_proxy_call_sync (proxy, -+ "SetFormatsLocale", -+ g_variant_new ("(s)", formats_locale), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, -+ &error); -+ if (!ret) { -+ g_warning ("Couldn't set FormatsLocale: %s", error->message); -+ g_error_free (error); -+ } else -+ g_variant_unref (ret); -+ -+ g_object_unref (proxy); -+ g_free (user_path); -+} - - static void - update_settings_cb (GtkTreeSelection *selection, gpointer user_data) -@@ -159,7 +200,6 @@ - gchar *active_id; - GtkWidget *treeview; - GSettings *locale_settings; -- gchar *current_setting; - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; -@@ -169,13 +209,10 @@ - treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector")); - - locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); -- current_setting = g_settings_get_string (locale_settings, "region"); - -- if (g_strcmp0 (active_id, current_setting) != 0) { -- g_settings_set_string (locale_settings, "region", active_id); -- } -+ set_formats_locale (active_id); -+ locale_settings_changed (locale_settings, NULL, builder); - -- g_free (current_setting); - g_free (active_id); - } - -@@ -184,7 +221,7 @@ - { - gchar *current_setting; - -- current_setting = g_settings_get_string (locale_settings, "region"); -+ current_setting = cc_common_language_get_property ("FormatsLocale"); - select_region (treeview, current_setting); - g_free (current_setting); - } -@@ -213,7 +250,6 @@ - populate_regions (GtkBuilder *builder, const gchar *current_lang) - { - gchar *current_region; -- GSettings *locale_settings; - GHashTable *ht; - GHashTableIter htiter; - GtkTreeModel *model; -@@ -228,11 +264,10 @@ - g_signal_handlers_block_by_func (selection, update_settings_cb, builder); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); -- locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); - - ht = cc_common_language_get_initial_regions (current_lang); - -- current_region = g_settings_get_string (locale_settings, "region"); -+ current_region = cc_common_language_get_property ("FormatsLocale"); - if (!current_region || !current_region[0]) { - current_region = g_strdup (current_lang); - } -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-system.c 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c 2013-03-15 17:48:09.379904608 +0100 -@@ -88,7 +88,7 @@ - gtk_widget_set_sensitive (button, TRUE); - } - --static void -+void - locale_settings_changed (GSettings *settings, - const gchar *key, - GtkBuilder *dialog) -@@ -96,7 +96,7 @@ - GtkWidget *label; - gchar *region, *display_region; - -- region = g_settings_get_string (locale_settings, "region"); -+ region = cc_common_language_get_property ("FormatsLocale"); - if (!region || !region[0]) { - label = WID ("user_display_language"); - region = g_strdup ((gchar*)g_object_get_data (G_OBJECT (label), "language")); -@@ -216,6 +216,16 @@ - } - } - -+static gchar * -+strip_quotes (const gchar *str) -+{ -+ if ((g_str_has_prefix (str, "\"") && g_str_has_suffix (str, "\"")) -+ || (g_str_has_prefix (str, "'") && g_str_has_suffix (str, "'"))) -+ return g_strndup (str + 1, strlen (str) - 2); -+ else -+ return g_strdup (str); -+} -+ - static void - on_localed_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, -@@ -244,33 +254,43 @@ - const gchar **strv; - gsize len; - gint i; -- const gchar *lang, *messages, *time; -+ gchar *lang, *language, *messages, *time; - gchar *name; - GtkWidget *label; - - strv = g_variant_get_strv (v, &len); - -- lang = messages = time = NULL; -+ lang = language = messages = time = NULL; - for (i = 0; strv[i]; i++) { - if (g_str_has_prefix (strv[i], "LANG=")) { -- lang = strv[i] + strlen ("LANG="); -+ lang = strip_quotes (strv[i] + strlen ("LANG=")); -+ } -+ else if (g_str_has_prefix (strv[i], "LANGUAGE=")) { -+ gchar *tmp = strip_quotes (strv[i] + strlen ("LANGUAGE=")); -+ gchar **tokens = g_strsplit (tmp, ":", 2); -+ language = g_strdup (tokens[0]); -+ g_free (tmp); -+ g_strfreev (tokens); - } - else if (g_str_has_prefix (strv[i], "LC_MESSAGES=")) { -- messages = strv[i] + strlen ("LC_MESSAGES="); -+ messages = strip_quotes (strv[i] + strlen ("LC_MESSAGES=")); - } - else if (g_str_has_prefix (strv[i], "LC_TIME=")) { -- time = strv[i] + strlen ("LC_TIME="); -+ time = strip_quotes (strv[i] + strlen ("LC_TIME=")); - } - } -- if (!messages) { -- messages = lang; -+ if (!language) { -+ if (messages) -+ language = g_strdup (messages); -+ else -+ language = g_strdup (lang); - } - if (!time) { -- time = lang; -+ time = g_strdup (lang); - } - -- if (messages) { -- name = gdm_get_language_from_name (messages, NULL); -+ if (language) { -+ name = gdm_get_language_from_name (language, NULL); - label = WID ("system_display_language"); - gtk_label_set_text (GTK_LABEL (label), name); - g_free (name); -@@ -285,6 +305,10 @@ - g_object_set_data_full (G_OBJECT (label), "region", g_strdup (time), g_free); - } - g_variant_unref (v); -+ g_free (lang); -+ g_free (language); -+ g_free (messages); -+ g_free (time); - } - - label = WID ("system_input_source"); -@@ -350,27 +374,44 @@ - GtkWidget *label; - GVariantBuilder *b; - gchar *s; -+ gchar *command; -+ gchar *lang; -+ GError *error = NULL; -+ gint i; - - label = WID ("user_display_language"); - language = g_object_get_data (G_OBJECT (label), "language"); - label = WID ("user_format"); - region = g_object_get_data (G_OBJECT (label), "region"); - -+ /* Get locale that corresponds to the language */ -+ command = g_strconcat ("/usr/share/language-tools/language2locale ", language, NULL); -+ if (!g_spawn_command_line_sync (command, &lang, NULL, NULL, &error)) { -+ g_warning ("Couldn't get LANG locale: %s", error->message); -+ g_error_free (error); -+ g_free (command); -+ return; -+ } -+ g_free (command); -+ g_strchomp (lang); -+ if (strlen (lang) == 0) { -+ g_warning ("Couldn't get LANG locale -- Copying interrupted"); -+ return; -+ } -+ - b = g_variant_builder_new (G_VARIANT_TYPE ("as")); -- s = g_strconcat ("LANG=", language, NULL); -+ s = g_strconcat ("LANG=", lang, NULL); - g_variant_builder_add (b, "s", s); -+ g_free (lang); - g_free (s); -- if (g_strcmp0 (language, region) != 0) { -- s = g_strconcat ("LC_TIME=", region, NULL); -- g_variant_builder_add (b, "s", s); -- g_free (s); -- s = g_strconcat ("LC_NUMERIC=", region, NULL); -- g_variant_builder_add (b, "s", s); -- g_free (s); -- s = g_strconcat ("LC_MONETARY=", region, NULL); -- g_variant_builder_add (b, "s", s); -- g_free (s); -- s = g_strconcat ("LC_MEASUREMENT=", region, NULL); -+ s = g_strconcat ("LANGUAGE=", language, NULL); -+ g_variant_builder_add (b, "s", s); -+ g_free (s); -+ const gchar *format_categories[] = { "LC_NUMERIC", "LC_TIME", -+ "LC_MONETARY", "LC_PAPER", "LC_IDENTIFICATION", "LC_NAME", -+ "LC_ADDRESS", "LC_TELEPHONE", "LC_MEASUREMENT", NULL }; -+ for (i = 0; format_categories[i] != NULL; i++) { -+ s = g_strconcat (format_categories[i], "=", region, NULL); - g_variant_builder_add (b, "s", s); - g_free (s); - } -@@ -525,7 +566,7 @@ - g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, input_sources_settings); - - /* Display user settings */ -- language = cc_common_language_get_current_language (); -+ language = cc_common_language_get_property ("Language"); - system_update_language (dialog, language); - g_free (language); - -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-system.h 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h 2013-03-15 17:20:48.927849976 +0100 -@@ -27,5 +27,8 @@ - void setup_system (GtkBuilder *builder); - void system_update_language (GtkBuilder *builder, - const gchar *language); -+void locale_settings_changed (GSettings *settings, -+ const gchar *key, -+ GtkBuilder *dialog); - - #endif -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel.ui 2013-03-15 17:20:48.939849976 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui 2013-03-15 17:20:48.931849976 +0100 -@@ -192,7 +192,7 @@ - - - -- True -+ False - False - icons - False diff -Nru gnome-control-center-3.6.3/debian/patches/53_use_ubuntu_help.patch gnome-control-center-3.6.3/debian/patches/53_use_ubuntu_help.patch --- gnome-control-center-3.6.3/debian/patches/53_use_ubuntu_help.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/53_use_ubuntu_help.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,282 +0,0 @@ -Description: Use pre-installed Ubuntu Desktop Guide instead of GNOME help when - running Unity -Forwarded: not-needed -Author: Jeremy Bicha -Index: gnome-control-center-3.6.2/panels/bluetooth/cc-bluetooth-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/bluetooth/cc-bluetooth-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/bluetooth/cc-bluetooth-panel.c 2012-11-02 19:29:57.639315414 -0400 -@@ -72,7 +72,10 @@ - static const char * - cc_bluetooth_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/bluetooth"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/bluetooth"; -+ else -+ return "help:gnome-help/bluetooth"; - } - - static void -Index: gnome-control-center-3.6.2/panels/color/cc-color-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/color/cc-color-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/color/cc-color-panel.c 2012-11-02 19:30:52.679313112 -0400 -@@ -2285,7 +2285,10 @@ - static const char * - cc_color_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/color"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/color"; -+ else -+ return "help:gnome-help/color"; - } - - static void -@@ -2567,6 +2570,12 @@ - g_signal_connect (widget, "realize", - G_CALLBACK (gcm_prefs_window_realize_cb), - prefs); -+ -+ widget = WID (priv->builder, "linkbutton_help"); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ g_object_set (G_OBJECT (widget), -+ "uri", "help:ubuntu-help/color-whyimportant", -+ NULL); - } - - void -Index: gnome-control-center-3.6.2/panels/datetime/cc-datetime-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/datetime/cc-datetime-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/datetime/cc-datetime-panel.c 2012-11-02 19:29:57.639315414 -0400 -@@ -178,7 +178,10 @@ - static const char * - cc_date_time_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/clock"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/clock"; -+ else -+ return "help:gnome-help/clock"; - } - - static void -Index: gnome-control-center-3.6.2/panels/display/cc-display-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/display/cc-display-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/display/cc-display-panel.c 2012-11-02 19:29:57.643315414 -0400 -@@ -205,7 +205,10 @@ - static const char * - cc_display_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/prefs-display"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/prefs-display"; -+ else -+ return "help:gnome-help/prefs-display"; - } - - static void -Index: gnome-control-center-3.6.2/panels/mouse/cc-mouse-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/mouse/cc-mouse-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/mouse/cc-mouse-panel.c 2012-11-02 19:29:57.643315414 -0400 -@@ -107,7 +107,10 @@ - static const char * - cc_mouse_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/mouse"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/mouse"; -+ else -+ return "help:gnome-help/mouse"; - } - - static void -Index: gnome-control-center-3.6.2/panels/network/cc-network-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/network/cc-network-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/network/cc-network-panel.c 2012-11-02 19:29:57.643315414 -0400 -@@ -232,7 +232,10 @@ - static const char * - cc_network_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/net"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/net"; -+ else -+ return "help:gnome-help/net"; - } - - static void -Index: gnome-control-center-3.6.2/panels/online-accounts/cc-online-accounts-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/online-accounts/cc-online-accounts-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/online-accounts/cc-online-accounts-panel.c 2012-11-02 19:29:57.643315414 -0400 -@@ -256,7 +256,10 @@ - static const char * - goa_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/accounts"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/accounts"; -+ else -+ return "help:gnome-help/accounts"; - } - - static void -Index: gnome-control-center-3.6.2/panels/power/cc-power-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/power/cc-power-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/power/cc-power-panel.c 2012-11-02 19:29:57.647315413 -0400 -@@ -124,7 +124,10 @@ - static const char * - cc_power_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/power"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/power"; -+ else -+ return "help:gnome-help/power"; - } - - static void -Index: gnome-control-center-3.6.2/panels/printers/cc-printers-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/printers/cc-printers-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/printers/cc-printers-panel.c 2012-11-02 19:29:57.647315413 -0400 -@@ -251,7 +251,10 @@ - static const char * - cc_printers_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/printing"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/printing"; -+ else -+ return "help:gnome-help/printing"; - } - - static void -Index: gnome-control-center-3.6.2/panels/screen/cc-screen-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/screen/cc-screen-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/screen/cc-screen-panel.c 2012-11-02 19:29:57.647315413 -0400 -@@ -146,7 +146,10 @@ - static const char * - cc_screen_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/prefs-display"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/prefs-display"; -+ else -+ return "help:gnome-help/prefs-display"; - } - - static void -Index: gnome-control-center-3.6.2/panels/sound/cc-sound-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/sound/cc-sound-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/sound/cc-sound-panel.c 2012-11-02 19:29:57.647315413 -0400 -@@ -70,7 +70,10 @@ - static const char * - cc_sound_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/media#sound"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/media#sound"; -+ else -+ return "help:gnome-help/media#sound"; - } - - static void -Index: gnome-control-center-3.6.2/panels/universal-access/cc-ua-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/universal-access/cc-ua-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/universal-access/cc-ua-panel.c 2012-11-02 19:29:57.651315413 -0400 -@@ -159,7 +159,10 @@ - static const char * - cc_ua_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/a11y"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/a11y"; -+ else -+ return "help:gnome-help/a11y"; - } - - static void -Index: gnome-control-center-3.6.2/panels/user-accounts/um-password-dialog.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/user-accounts/um-password-dialog.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/user-accounts/um-password-dialog.c 2012-11-02 19:29:57.651315413 -0400 -@@ -523,9 +523,14 @@ - - widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label"); - old_label = gtk_label_get_label (GTK_LABEL (widget)); -- label = g_strdup_printf ("%s", -- "help:gnome-help/user-goodpassword", -- old_label); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ label = g_strdup_printf ("%s", -+ "help:ubuntu-help/user-goodpassword", -+ old_label); -+ else -+ label = g_strdup_printf ("%s", -+ "help:gnome-help/user-goodpassword", -+ old_label); - gtk_label_set_markup (GTK_LABEL (widget), label); - g_free (label); - -Index: gnome-control-center-3.6.2/panels/user-accounts/um-user-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/user-accounts/um-user-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/user-accounts/um-user-panel.c 2012-11-02 19:29:57.651315413 -0400 -@@ -1372,7 +1372,10 @@ - static const char * - um_user_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/user-accounts"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/user-accounts"; -+ else -+ return "help:gnome-help/user-accounts"; - } - - static void -Index: gnome-control-center-3.6.2/panels/wacom/cc-wacom-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/wacom/cc-wacom-panel.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/panels/wacom/cc-wacom-panel.c 2012-11-02 19:29:57.651315413 -0400 -@@ -123,7 +123,10 @@ - static const char * - cc_wacom_panel_get_help_uri (CcPanel *panel) - { -- return "help:gnome-help/wacom"; -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ return "help:ubuntu-help/wacom"; -+ else -+ return "help:gnome-help/wacom"; - } - - static void -Index: gnome-control-center-3.6.2/shell/control-center.c -=================================================================== ---- gnome-control-center-3.6.2.orig/shell/control-center.c 2012-11-02 19:29:55.031315523 -0400 -+++ gnome-control-center-3.6.2/shell/control-center.c 2012-11-02 19:30:16.431314628 -0400 -@@ -175,8 +175,12 @@ - - if (panel) - uri = cc_panel_get_help_uri (panel); -- -- gtk_show_uri (gtk_widget_get_screen (window), -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ gtk_show_uri (gtk_widget_get_screen (window), -+ uri ? uri : "help:ubuntu-help/prefs", -+ GDK_CURRENT_TIME, NULL); -+ else -+ gtk_show_uri (gtk_widget_get_screen (window), - uri ? uri : "help:gnome-help/prefs", - GDK_CURRENT_TIME, NULL); - } diff -Nru gnome-control-center-3.6.3/debian/patches/54_enable_alt_tap_in_shortcut.patch gnome-control-center-3.6.3/debian/patches/54_enable_alt_tap_in_shortcut.patch --- gnome-control-center-3.6.3/debian/patches/54_enable_alt_tap_in_shortcut.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/54_enable_alt_tap_in_shortcut.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -Index: gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/keyboard/keyboard-shortcuts.c 2012-11-21 18:09:33.690816155 +0100 -+++ gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c 2012-11-21 18:09:34.222816183 +0100 -@@ -1716,7 +1716,7 @@ - gtk_tree_view_append_column (treeview, column); - - renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, -- "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, -+ "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_MODIFIER_TAP, - NULL); - - g_signal_connect (treeview, "button_press_event", -Index: gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/keyboard/cc-keyboard-item.c 2012-05-24 16:20:10.000000000 +0200 -+++ gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c 2012-11-21 18:09:34.222816183 +0100 -@@ -143,14 +143,25 @@ - const char *value, - gboolean set_backend) - { -+ /* don't reassign or key in the callback to the binding itself (as it's invalid for the cell renderer) */ -+ if ((g_strcmp0 (value, "") == 0) || (g_strcmp0 (value, "") == 0)) -+ return; -+ - g_free (item->binding); - item->binding = g_strdup (value); - binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); - -+ const char *key; -+ char *cheated_modifier = NULL; -+ if (g_strcmp0 (item->binding, "Alt_L") == 0) -+ cheated_modifier = g_strdup_printf ("<%s>", item->binding); -+ - if (set_backend == FALSE) - return; - -- settings_set_binding (item->settings, item->key, item->binding); -+ settings_set_binding (item->settings, item->key, cheated_modifier ? cheated_modifier: item->binding); -+ -+ g_free (cheated_modifier); - } - - const char * -@@ -441,6 +452,13 @@ - item->settings = g_settings_new (item->schema); - item->binding = settings_get_binding (item->settings, item->key); - item->editable = g_settings_is_writable (item->settings, item->key); -+ -+ if ((g_strcmp0 (item->binding, "") == 0) || (g_strcmp0 (item->binding, "") == 0)) -+ { -+ g_free (item->binding); -+ item->binding = g_strdup ("Alt_L"); -+ } -+ - binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); - - signal_name = g_strdup_printf ("changed::%s", item->key); diff -Nru gnome-control-center-3.6.3/debian/patches/55_user_accounts_hide_controls.patch gnome-control-center-3.6.3/debian/patches/55_user_accounts_hide_controls.patch --- gnome-control-center-3.6.3/debian/patches/55_user_accounts_hide_controls.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/55_user_accounts_hide_controls.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -Index: gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/user-accounts/um-password-dialog.c 2013-01-22 15:11:55.971943861 -0500 -+++ gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c 2013-01-22 15:11:55.959943861 -0500 -@@ -52,6 +52,7 @@ - GtkWidget *ok_button; - - UmUser *user; -+ gboolean using_ecryptfs; - - GtkWidget *old_password_label; - GtkWidget *old_password_entry; -@@ -471,6 +472,38 @@ - } - } - -+int _is_gdm_running = -1; -+gboolean -+is_gdm_running (void) -+{ -+ if (_is_gdm_running == -1) { -+ GDBusProxy *proxy; -+ gchar *owner_name; -+ -+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, -+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | -+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | -+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, -+ NULL, -+ "org.gnome.DisplayManager", -+ "/org/gnome/DisplayManager/Manager", -+ "org.gnome.DisplayManager.Manager", -+ NULL, NULL); -+ -+ if (proxy == NULL) -+ return FALSE; -+ -+ owner_name = g_dbus_proxy_get_name_owner (proxy); -+ -+ g_object_unref (proxy); -+ g_free (owner_name); -+ -+ _is_gdm_running = (owner_name != NULL) ? 1 : 0; -+ } -+ -+ return _is_gdm_running; -+} -+ - UmPasswordDialog * - um_password_dialog_new (void) - { -@@ -591,6 +624,13 @@ - G_CALLBACK (entry_size_changed), widget); - um->normal_hint_label = widget; - -+ if (!is_gdm_running ()) { -+ widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-hint-label"); -+ gtk_widget_hide (widget); -+ gtk_widget_hide (um->normal_hint_entry); -+ gtk_widget_hide (um->normal_hint_label); -+ } -+ - um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator"); - - um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); -@@ -625,6 +665,12 @@ - - gtk_tree_model_get (model, iter, 1, &mode, -1); - -+ if (mode == 1 && !is_gdm_running ()) -+ return FALSE; -+ -+ if (mode == 2 && um->using_ecryptfs) -+ return FALSE; -+ - if (mode == 3 && locked) - return FALSE; - -@@ -651,6 +697,8 @@ - if (user) { - um->user = g_object_ref (user); - -+ um->using_ecryptfs = is_using_ecryptfs (um_user_get_user_name (user)); -+ - pixbuf = um_user_render_icon (user, FALSE, 48); - gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf); - g_object_unref (pixbuf); -Index: gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/user-accounts/um-user-panel.c 2013-01-22 15:11:55.971943861 -0500 -+++ gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c 2013-01-22 15:12:18.031943282 -0500 -@@ -629,7 +629,10 @@ - /* Autologin: show when local account */ - widget = get_widget (d, "autologin-switch"); - label = get_widget (d, "autologin-label"); -- show = um_user_is_local_account (user); -+ /* Don't show autologin option if ecryptfs is in use, because it won't -+ work if user turns it on. */ -+ show = um_user_is_local_account (user) && -+ !is_using_ecryptfs (um_user_get_user_name (user)); - gtk_widget_set_visible (widget, show); - gtk_widget_set_visible (label, show); - } -Index: gnome-control-center-3.6.3/panels/user-accounts/um-utils.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/user-accounts/um-utils.c 2013-01-22 15:11:55.971943861 -0500 -+++ gnome-control-center-3.6.3/panels/user-accounts/um-utils.c 2013-01-22 15:11:55.963943861 -0500 -@@ -746,3 +746,27 @@ - g_string_free (item3, TRUE); - g_string_free (item4, TRUE); - } -+ -+gboolean -+is_using_ecryptfs (const gchar *name) -+{ -+ gboolean using_ecryptfs = FALSE; -+ int status; -+ gchar *prog; -+ gchar *cmd; -+ -+ prog = g_find_program_in_path ("ecryptfs-verify"); -+ if (prog != NULL) { -+ gchar *cmd = g_strdup_printf("'%s' -h -u '%s'", prog, name); -+ -+ if (g_spawn_command_line_sync (cmd, NULL, NULL, &status, NULL)) { -+ if (status == 0) -+ using_ecryptfs = TRUE; -+ } -+ -+ g_free (prog); -+ g_free (cmd); -+ } -+ -+ return using_ecryptfs; -+} -Index: gnome-control-center-3.6.3/panels/user-accounts/um-utils.h -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/user-accounts/um-utils.h 2013-01-22 15:11:55.971943861 -0500 -+++ gnome-control-center-3.6.3/panels/user-accounts/um-utils.h 2013-01-22 15:11:55.963943861 -0500 -@@ -65,6 +65,8 @@ - void generate_username_choices (const gchar *name, - GtkListStore *store); - -+gboolean is_using_ecryptfs (const gchar *name); -+ - G_END_DECLS - - #endif diff -Nru gnome-control-center-3.6.3/debian/patches/56_use_ubuntu_info_branding.patch gnome-control-center-3.6.3/debian/patches/56_use_ubuntu_info_branding.patch --- gnome-control-center-3.6.3/debian/patches/56_use_ubuntu_info_branding.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/56_use_ubuntu_info_branding.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Index: b/panels/info/cc-info-panel.c -=================================================================== ---- a/panels/info/cc-info-panel.c -+++ b/panels/info/cc-info-panel.c -@@ -1706,6 +1706,8 @@ - g_free (text); - } - -+ gtk_widget_hide (WID ("version_label")); -+ - glibtop_get_mem (&mem); - text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS); - widget = WID ("memory_label"); -Index: b/panels/info/info.ui -=================================================================== ---- a/panels/info/info.ui -+++ b/panels/info/info.ui -@@ -242,7 +242,7 @@ - - True - False -- GnomeLogoVerticalMedium.svg -+ UbuntuLogo.png - - - False diff -Nru gnome-control-center-3.6.3/debian/patches/58_hide_gdm_notifications.patch gnome-control-center-3.6.3/debian/patches/58_hide_gdm_notifications.patch --- gnome-control-center-3.6.3/debian/patches/58_hide_gdm_notifications.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/58_hide_gdm_notifications.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Description: Hide "Show notifications when locked" settings when running - Unity. You currently need GNOME Shell running on GDM for that to work. -Forwarded: not-needed -Author: Jeremy Bicha -Index: gnome-control-center-3.6.2/panels/screen/cc-screen-panel.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/screen/cc-screen-panel.c 2012-11-03 19:10:00.926617924 -0400 -+++ gnome-control-center-3.6.2/panels/screen/cc-screen-panel.c 2012-11-03 19:17:14.902599774 -0400 -@@ -545,6 +545,8 @@ - "show-notifications", - widget, "active", - G_SETTINGS_BIND_DEFAULT); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ gtk_widget_hide (widget); - - update_lock_screen_sensitivity (self); - diff -Nru gnome-control-center-3.6.3/debian/patches/58_ubuntu_icon_views_redesign.patch gnome-control-center-3.6.3/debian/patches/58_ubuntu_icon_views_redesign.patch --- gnome-control-center-3.6.3/debian/patches/58_ubuntu_icon_views_redesign.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/58_ubuntu_icon_views_redesign.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -Index: gnome-control-center-3.6.3/shell/gnome-control-center.c -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/gnome-control-center.c 2012-11-24 10:39:18.476282140 -0500 -+++ gnome-control-center-3.6.3/shell/gnome-control-center.c 2012-11-24 10:52:26.776249171 -0500 -@@ -50,7 +50,8 @@ - * for the user than resizing vertically - * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ - #define FIXED_WIDTH 740 --#define FIXED_HEIGHT 636 -+#define UNITY_FIXED_WIDTH 850 -+#define FIXED_HEIGHT 650 - #define SMALL_SCREEN_FIXED_HEIGHT 400 - - #define MIN_ICON_VIEW_HEIGHT 300 -@@ -910,8 +911,12 @@ - gtk_widget_show (W (priv->builder, "search-entry")); - gtk_widget_hide (W (priv->builder, "lock-button")); - -- gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), -- FIXED_WIDTH, NULL, &nat_height); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), -+ UNITY_FIXED_WIDTH, NULL, &nat_height); -+ else -+ gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), -+ FIXED_WIDTH, NULL, &nat_height); - gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), - priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); - } -@@ -921,12 +926,22 @@ - gtk_widget_hide (W (priv->builder, "search-entry")); - /* set the scrolled window small so that it doesn't force - the window to be larger than this panel */ -- gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), -- FIXED_WIDTH, NULL, &nat_height); -- gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); -- gtk_window_resize (GTK_WINDOW (priv->window), -- FIXED_WIDTH, -- nat_height); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { -+ gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), -+ UNITY_FIXED_WIDTH, NULL, &nat_height); -+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); -+ gtk_window_resize (GTK_WINDOW (priv->window), -+ UNITY_FIXED_WIDTH, -+ nat_height); -+ } -+ else { -+ gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), -+ FIXED_WIDTH, NULL, &nat_height); -+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); -+ gtk_window_resize (GTK_WINDOW (priv->window), -+ FIXED_WIDTH, -+ nat_height); -+ } - } - } - -@@ -1373,7 +1388,10 @@ - /* Main scrolled window */ - priv->scrolled_window = W (priv->builder, "scrolledwindow1"); - -- gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); -+ if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) -+ gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); -+ else -+ gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); - priv->main_vbox = W (priv->builder, "main-vbox"); - g_signal_connect (priv->notebook, "notify::page", - G_CALLBACK (notebook_page_notify_cb), priv); diff -Nru gnome-control-center-3.6.3/debian/patches/59_install_gcm_components_on_demand.patch gnome-control-center-3.6.3/debian/patches/59_install_gcm_components_on_demand.patch --- gnome-control-center-3.6.3/debian/patches/59_install_gcm_components_on_demand.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/59_install_gcm_components_on_demand.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -Index: b/panels/color/cc-color-panel.c -=================================================================== ---- a/panels/color/cc-color-panel.c -+++ b/panels/color/cc-color-panel.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - #include "cc-color-panel.h" - -@@ -260,32 +261,148 @@ - } - - static void --gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) -+gcm_packagekit_finished_cb (GObject *source, GAsyncResult *res, gpointer user_data) -+{ -+ GPtrArray *argv = (GPtrArray *)user_data; -+ GVariant *reply; -+ GError *error = NULL; -+ gboolean ret; -+ -+ reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); -+ g_variant_unref (reply); -+ -+ if (error != NULL) -+ { -+ g_warning ("failed to install required component: %s", error->message); -+ g_ptr_array_unref (argv); -+ g_error_free (error); -+ return; -+ } -+ -+ ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, -+ NULL, NULL, NULL, &error); -+ g_ptr_array_unref (argv); -+ if (!ret) -+ { -+ g_warning ("failed to run command: %s", error->message); -+ g_error_free (error); -+ } -+} -+ -+struct gcm_packagekit_closure_data -+{ -+ GPtrArray *argv; -+ guint xid; -+}; -+ -+static void -+gcm_packagekit_proxy_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) -+{ -+ struct gcm_packagekit_closure_data *data = -+ (struct gcm_packagekit_closure_data *)user_data; -+ GDBusProxy *session_installer; -+ GVariantBuilder *builder; -+ GError *error = NULL; -+ -+ session_installer = g_dbus_proxy_new_for_bus_finish (res, &error); -+ if (error != NULL) -+ { -+ g_warning ("failed to connect to PackageKit interface: %s", -+ error->message); -+ g_ptr_array_unref (data->argv); -+ g_free (data); -+ g_error_free (error); -+ return; -+ } -+ -+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); -+ g_variant_builder_add (builder, "s", -+ g_ptr_array_index (data->argv, 0)); -+ g_dbus_proxy_call (session_installer, -+ "InstallProvideFiles", -+ g_variant_new ("(uass)", -+ data->xid, -+ builder, -+ "hide-finished" -+ ), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, -+ &gcm_packagekit_finished_cb, -+ data->argv); -+ -+ g_free (data); -+ g_variant_builder_unref (builder); -+} -+ -+static void -+gcm_prefs_install_component (guint xid, GPtrArray *argv) -+{ -+ struct gcm_packagekit_closure_data *data; -+ data = g_malloc (sizeof (*data)); -+ data->argv = argv; -+ data->xid = xid; -+ g_ptr_array_ref (data->argv); -+ -+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, -+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | -+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, -+ NULL, -+ "org.freedesktop.PackageKit", -+ "/org/freedesktop/PackageKit", -+ "org.freedesktop.PackageKit.Modify", -+ NULL, -+ &gcm_packagekit_proxy_ready_cb, -+ data); -+} -+ -+static void -+gcm_prefs_run_maybe_install (guint xid, gchar *filename, GPtrArray *argv) - { - gboolean ret; - GError *error = NULL; -+ -+ ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, -+ NULL, NULL, NULL, &error); -+ if (!ret) -+ { -+ if ((error->domain == g_spawn_error_quark ()) && -+ (error->code == G_SPAWN_ERROR_NOENT)) -+ { -+ gcm_prefs_install_component (xid, argv); -+ } -+ else -+ { -+ g_warning ("failed to run command: %s", error->message); -+ } -+ g_error_free (error); -+ } -+} -+ -+static void -+gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) -+{ - guint xid; - GPtrArray *argv; -+ gchar *calibrater_filename; - CcColorPanelPrivate *priv = prefs->priv; - - /* get xid */ - xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); - -+ calibrater_filename = g_build_filename (BINDIR, "gcm-calibrate", NULL); -+ - /* run with modal set */ - argv = g_ptr_array_new_with_free_func (g_free); -- g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-calibrate", NULL)); -+ g_ptr_array_add (argv, calibrater_filename); - g_ptr_array_add (argv, g_strdup ("--device")); - g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device))); - g_ptr_array_add (argv, g_strdup ("--parent-window")); - g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); - g_ptr_array_add (argv, NULL); -- ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, -- NULL, NULL, NULL, &error); -- if (!ret) -- { -- g_warning ("failed to run calibrate: %s", error->message); -- g_error_free (error); -- } -+ -+ gcm_prefs_run_maybe_install (xid, calibrater_filename, argv); -+ - g_ptr_array_unref (argv); - } - -@@ -656,10 +773,9 @@ - GtkTreeModel *model; - GtkTreeSelection *selection; - gchar *options = NULL; -+ gchar *viewer_filename; - GPtrArray *argv = NULL; - guint xid; -- gboolean ret; -- GError *error = NULL; - CcColorPanelPrivate *priv = prefs->priv; - - /* get the selected row */ -@@ -677,21 +793,17 @@ - /* get xid */ - xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); - -+ viewer_filename = g_build_filename (BINDIR, "gcm-viewer", NULL); - /* open up gcm-viewer as a info pane */ - argv = g_ptr_array_new_with_free_func (g_free); -- g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-viewer", NULL)); -+ g_ptr_array_add (argv, viewer_filename); - g_ptr_array_add (argv, g_strdup ("--profile")); - g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile))); - g_ptr_array_add (argv, g_strdup ("--parent-window")); - g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); - g_ptr_array_add (argv, NULL); -- ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, -- NULL, NULL, NULL, &error); -- if (!ret) -- { -- g_warning ("failed to run calibrate: %s", error->message); -- g_error_free (error); -- } -+ -+ gcm_prefs_run_maybe_install (xid, viewer_filename, argv); - - g_ptr_array_unref (argv); - g_free (options); -@@ -995,7 +1107,6 @@ - { - GtkWidget *widget; - CdDeviceRelation relation; -- gchar *s; - CcColorPanelPrivate *priv = prefs->priv; - - /* get profile */ -@@ -1026,13 +1137,7 @@ - /* allow getting profile info */ - widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, - "toolbutton_profile_view")); -- if ((s = g_find_program_in_path ("gcm-viewer"))) -- { -- gtk_widget_set_sensitive (widget, TRUE); -- g_free (s); -- } -- else -- gtk_widget_set_sensitive (widget, FALSE); -+ gtk_widget_set_sensitive (widget, TRUE); - - /* hide device specific stuff */ - widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, diff -Nru gnome-control-center-3.6.3/debian/patches/60_ubuntu_nav_bar.patch gnome-control-center-3.6.3/debian/patches/60_ubuntu_nav_bar.patch --- gnome-control-center-3.6.3/debian/patches/60_ubuntu_nav_bar.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/60_ubuntu_nav_bar.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,406 +0,0 @@ -# Description: set a navigation bar in the g-c-c shell -# UbuntuSpecific: yes -# -=== modified file 'shell/Makefile.am' -Index: gnome-control-center-3.6.3/shell/Makefile.am -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/Makefile.am 2012-10-01 11:39:00.000000000 +0200 -+++ gnome-control-center-3.6.3/shell/Makefile.am 2012-11-22 10:20:59.485282338 +0100 -@@ -26,6 +26,8 @@ - cc-shell-item-view.h \ - cc-shell-model.c \ - cc-shell-model.h \ -+ cc-shell-nav-bar.c \ -+ cc-shell-nav-bar.h \ - cc-editable-entry.c \ - cc-editable-entry.h \ - cc-panel.c \ -Index: gnome-control-center-3.6.3/shell/cc-shell-marshal.list -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/cc-shell-marshal.list 2011-11-07 18:22:02.000000000 +0100 -+++ gnome-control-center-3.6.3/shell/cc-shell-marshal.list 2012-11-22 10:20:56.873282212 +0100 -@@ -1 +1,2 @@ - VOID:STRING,STRING,STRING -+VOID:VOID -Index: gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c 2012-11-22 10:20:56.873282212 +0100 -@@ -0,0 +1,150 @@ -+/* -+ * Copyright 2012 Canonical -+ * -+ * The Control Center 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. -+ * -+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Author: Aurélien Gâteau -+ */ -+ -+#include "cc-shell-nav-bar.h" -+#include "cc-shell-marshal.h" -+ -+#include -+ -+G_DEFINE_TYPE (CcShellNavBar, cc_shell_nav_bar, GTK_TYPE_BOX) -+ -+#define SHELL_NAV_BAR_PRIVATE(o) \ -+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SHELL_NAV_BAR, CcShellNavBarPrivate)) -+ -+struct _CcShellNavBarPrivate -+{ -+ GtkWidget *home_button; -+ GtkWidget *detail_button; -+}; -+ -+enum -+{ -+ HOME_CLICKED, -+ LAST_SIGNAL -+}; -+ -+static guint signals[LAST_SIGNAL] = {0,}; -+ -+static void -+cc_shell_nav_bar_get_property (GObject *object, -+ guint property_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (property_id) -+ { -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -+ } -+} -+ -+static void -+cc_shell_nav_bar_set_property (GObject *object, -+ guint property_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (property_id) -+ { -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -+ } -+} -+ -+static void -+cc_shell_nav_bar_dispose (GObject *object) -+{ -+ G_OBJECT_CLASS (cc_shell_nav_bar_parent_class)->dispose (object); -+} -+ -+static void -+cc_shell_nav_bar_finalize (GObject *object) -+{ -+ G_OBJECT_CLASS (cc_shell_nav_bar_parent_class)->finalize (object); -+} -+ -+static void -+home_button_clicked_cb (GtkButton *button, -+ CcShellNavBar *bar) -+{ -+ g_signal_emit (bar, signals[HOME_CLICKED], 0); -+} -+ -+static void -+cc_shell_nav_bar_class_init (CcShellNavBarClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ -+ g_type_class_add_private (klass, sizeof (CcShellNavBarPrivate)); -+ -+ object_class->get_property = cc_shell_nav_bar_get_property; -+ object_class->set_property = cc_shell_nav_bar_set_property; -+ object_class->dispose = cc_shell_nav_bar_dispose; -+ object_class->finalize = cc_shell_nav_bar_finalize; -+ -+ signals[HOME_CLICKED] = g_signal_new ("home-clicked", -+ CC_TYPE_SHELL_NAV_BAR, -+ G_SIGNAL_RUN_FIRST, -+ 0, -+ NULL, -+ NULL, -+ cc_shell_marshal_VOID__VOID, -+ G_TYPE_NONE, -+ 0); -+} -+ -+static void -+cc_shell_nav_bar_init (CcShellNavBar *self) -+{ -+ self->priv = SHELL_NAV_BAR_PRIVATE (self); -+ self->priv->home_button = gtk_button_new_with_mnemonic (_("_All Settings")); -+ self->priv->detail_button = gtk_button_new(); -+ -+ gtk_box_pack_start (GTK_BOX(self), self->priv->home_button, FALSE, FALSE, 0); -+ gtk_box_pack_start (GTK_BOX(self), self->priv->detail_button, FALSE, FALSE, 0); -+ -+ gtk_widget_show (self->priv->home_button); -+ -+ g_signal_connect (self->priv->home_button, "clicked", -+ G_CALLBACK (home_button_clicked_cb), self); -+ -+ GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(self)); -+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED); -+ gtk_style_context_add_class (context, "breadcrumbs"); -+} -+ -+GtkWidget * -+cc_shell_nav_bar_new (void) -+{ -+ return g_object_new (CC_TYPE_SHELL_NAV_BAR, NULL); -+} -+ -+void -+cc_shell_nav_bar_show_detail_button (CcShellNavBar *bar, const gchar *label) -+{ -+ gtk_widget_show (bar->priv->detail_button); -+ gtk_button_set_label (GTK_BUTTON (bar->priv->detail_button), label); -+} -+ -+void -+cc_shell_nav_bar_hide_detail_button (CcShellNavBar *bar) -+{ -+ gtk_widget_hide (bar->priv->detail_button); -+} -Index: gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h 2012-11-22 10:20:56.877282212 +0100 -@@ -0,0 +1,76 @@ -+/* -+ * Copyright 2012 Canonical -+ * -+ * The Control Center 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. -+ * -+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, -+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Author: Aurélien Gâteau -+ */ -+ -+#ifndef _CC_SHELL_NAV_BAR_H -+#define _CC_SHELL_NAV_BAR_H -+ -+#include -+ -+G_BEGIN_DECLS -+ -+#define CC_TYPE_SHELL_NAV_BAR cc_shell_nav_bar_get_type() -+ -+#define CC_SHELL_NAV_BAR(obj) \ -+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ -+ CC_TYPE_SHELL_NAV_BAR, CcShellNavBar)) -+ -+#define CC_SHELL_NAV_BAR_CLASS(klass) \ -+ (G_TYPE_CHECK_CLASS_CAST ((klass), \ -+ CC_TYPE_SHELL_NAV_BAR, CcShellNavBarClass)) -+ -+#define CC_IS_SHELL_NAV_BAR(obj) \ -+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ -+ CC_TYPE_SHELL_NAV_BAR)) -+ -+#define CC_IS_SHELL_NAV_BAR_CLASS(klass) \ -+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ -+ CC_TYPE_SHELL_NAV_BAR)) -+ -+#define CC_SHELL_NAV_BAR_GET_CLASS(obj) \ -+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ -+ CC_TYPE_SHELL_NAV_BAR, CcShellNavBarClass)) -+ -+typedef struct _CcShellNavBar CcShellNavBar; -+typedef struct _CcShellNavBarClass CcShellNavBarClass; -+typedef struct _CcShellNavBarPrivate CcShellNavBarPrivate; -+ -+struct _CcShellNavBar -+{ -+ GtkBox parent; -+ -+ CcShellNavBarPrivate *priv; -+}; -+ -+struct _CcShellNavBarClass -+{ -+ GtkBoxClass parent_class; -+}; -+ -+GType cc_shell_nav_bar_get_type (void) G_GNUC_CONST; -+ -+GtkWidget *cc_shell_nav_bar_new (void); -+ -+void cc_shell_nav_bar_show_detail_button (CcShellNavBar *bar, const gchar *label); -+ -+void cc_shell_nav_bar_hide_detail_button (CcShellNavBar *bar); -+ -+G_END_DECLS -+ -+#endif /* _CC_SHELL_NAV_BAR_H */ -Index: gnome-control-center-3.6.3/shell/gnome-control-center.c -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/gnome-control-center.c 2012-11-22 10:20:56.833282210 +0100 -+++ gnome-control-center-3.6.3/shell/gnome-control-center.c 2012-11-22 10:20:59.485282338 +0100 -@@ -38,6 +38,7 @@ - #include "cc-shell.h" - #include "cc-shell-category-view.h" - #include "cc-shell-model.h" -+#include "cc-shell-nav-bar.h" - - G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) - -@@ -75,6 +76,7 @@ - GtkWidget *search_entry; - GtkWidget *lock_button; - GPtrArray *custom_widgets; -+ GtkWidget *nav_bar; - - GMenuTree *menu_tree; - GtkListStore *store; -@@ -237,6 +239,7 @@ - /* switch to the new panel */ - gtk_widget_show (box); - notebook_select_page (priv->notebook, box); -+ cc_shell_nav_bar_show_detail_button (CC_SHELL_NAV_BAR(shell->priv->nav_bar), name); - - /* set the title of the window */ - icon_name = get_icon_name_from_g_icon (gicon); -@@ -299,6 +302,8 @@ - - /* clear any custom widgets */ - _shell_remove_all_custom_widgets (priv); -+ -+ cc_shell_nav_bar_hide_detail_button (CC_SHELL_NAV_BAR (priv->nav_bar)); - } - - void -@@ -902,11 +907,8 @@ - - child = notebook_get_selected_page (GTK_WIDGET (notebook)); - -- /* make sure the home button is shown on all pages except the overview page */ -- - if (child == priv->scrolled_window || child == priv->search_scrolled) - { -- gtk_widget_hide (W (priv->builder, "home-button")); - gtk_widget_show (W (priv->builder, "search-entry")); - gtk_widget_hide (W (priv->builder, "lock-button")); - -@@ -917,7 +919,6 @@ - } - else - { -- gtk_widget_show (W (priv->builder, "home-button")); - gtk_widget_hide (W (priv->builder, "search-entry")); - /* set the scrolled window small so that it doesn't force - the window to be larger than this panel */ -@@ -1332,6 +1333,7 @@ - GError *err = NULL; - GnomeControlCenterPrivate *priv; - GdkScreen *screen; -+ GtkWidget *widget; - - priv = self->priv = CONTROL_CENTER_PRIVATE (self); - -@@ -1378,8 +1380,14 @@ - g_signal_connect (priv->notebook, "notify::page", - G_CALLBACK (notebook_page_notify_cb), priv); - -- g_signal_connect (gtk_builder_get_object (priv->builder, "home-button"), -- "clicked", G_CALLBACK (home_button_clicked_cb), self); -+ priv->nav_bar = cc_shell_nav_bar_new (); -+ widget = W (priv->builder, "hbox1"); -+ gtk_box_pack_start (GTK_BOX (widget), priv->nav_bar, FALSE, FALSE, 0); -+ gtk_box_reorder_child (GTK_BOX (widget), priv->nav_bar, 0); -+ gtk_widget_show (priv->nav_bar); -+ -+ g_signal_connect (priv->nav_bar, -+ "home-clicked", G_CALLBACK (home_button_clicked_cb), self); - - /* keep a list of custom widgets to unload on panel change */ - priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); -Index: gnome-control-center-3.6.3/shell/shell.ui -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/shell.ui 2012-11-14 12:42:44.000000000 +0100 -+++ gnome-control-center-3.6.3/shell/shell.ui 2012-11-22 10:21:52.369284899 +0100 -@@ -34,36 +34,6 @@ - - True - -- -- True -- False -- 0 -- 1 -- none -- False -- -- -- False -- True -- True -- True -- False -- image1 -- True -- -- -- All Settings -- -- -- -- -- -- -- False -- 0 -- -- -- - - True - 1 -@@ -93,7 +63,7 @@ - - - -- 1 -+ 0 - - - -@@ -172,13 +142,6 @@ - - - -- -- vertical -- -- -- -- -- - - True - False diff -Nru gnome-control-center-3.6.3/debian/patches/61_workaround_online_account.patch gnome-control-center-3.6.3/debian/patches/61_workaround_online_account.patch --- gnome-control-center-3.6.3/debian/patches/61_workaround_online_account.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/61_workaround_online_account.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# Description: Don't show goa in Unity, we use uoa there -# Upstream: the change is ubuntu specific -# -Index: gnome-control-center-3.3.91/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.3.91.orig/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 2012-03-05 15:04:55.000000000 +0100 -+++ gnome-control-center-3.3.91/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 2012-03-06 17:52:14.907083003 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=Online Accounts diff -Nru gnome-control-center-3.6.3/debian/patches/64_restore_terminal_keyboard_shortcut.patch gnome-control-center-3.6.3/debian/patches/64_restore_terminal_keyboard_shortcut.patch --- gnome-control-center-3.6.3/debian/patches/64_restore_terminal_keyboard_shortcut.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/64_restore_terminal_keyboard_shortcut.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Index: gnome-control-center-3.4.2/panels/keyboard/01-launchers.xml.in -=================================================================== ---- gnome-control-center-3.4.2.orig/panels/keyboard/01-launchers.xml.in 2011-08-25 11:09:31.000000000 -0400 -+++ gnome-control-center-3.4.2/panels/keyboard/01-launchers.xml.in 2012-08-25 23:34:01.889092065 -0400 -@@ -7,6 +7,8 @@ - - - -+ -+ - - - diff -Nru gnome-control-center-3.6.3/debian/patches/90_force_fallback.patch gnome-control-center-3.6.3/debian/patches/90_force_fallback.patch --- gnome-control-center-3.6.3/debian/patches/90_force_fallback.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/90_force_fallback.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Index: b/panels/info/info.ui -=================================================================== ---- a/panels/info/info.ui -+++ b/panels/info/info.ui -@@ -1191,7 +1191,7 @@ - - - -- True -+ False - False - 1 - Forced _Fallback Mode -@@ -1240,7 +1240,7 @@ - - - -- True -+ False - False - start - center diff -Nru gnome-control-center-3.6.3/debian/patches/91_unity_no_printing_panel.patch gnome-control-center-3.6.3/debian/patches/91_unity_no_printing_panel.patch --- gnome-control-center-3.6.3/debian/patches/91_unity_no_printing_panel.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/91_unity_no_printing_panel.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -diff -Nur gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in gnome-control-center-3.6.3.new/panels/printers/gnome-printers-panel.desktop.in.in ---- gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in 2013-03-19 11:48:12.950319345 +0100 -+++ gnome-control-center-3.6.3.new/panels/printers/gnome-printers-panel.desktop.in.in 2013-03-19 11:47:56.902318811 +0100 -@@ -8,7 +8,7 @@ - StartupNotify=true - # The X-GNOME-Settings-Panel is necessary to show in the main shell UI - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Settings-Panel=printers - # Translators: those are keywords for the printing control-center panel - _Keywords=Printer;Queue;Print;Paper;Ink;Toner; diff -Nru gnome-control-center-3.6.3/debian/patches/92_ubuntu_system_proxy.patch gnome-control-center-3.6.3/debian/patches/92_ubuntu_system_proxy.patch --- gnome-control-center-3.6.3/debian/patches/92_ubuntu_system_proxy.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/92_ubuntu_system_proxy.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,217 +0,0 @@ -Index: gnome-control-center-3.6.3/panels/network/net-proxy.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/network/net-proxy.c 2013-04-16 16:14:41.159226157 +0200 -+++ gnome-control-center-3.6.3/panels/network/net-proxy.c 2013-04-16 16:14:59.847226780 +0200 -@@ -25,8 +25,14 @@ - #include - #include - -+#include -+#include -+#include -+ - #include "net-proxy.h" - -+ -+ - #define NET_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NET_TYPE_PROXY, NetProxyPrivate)) - - struct _NetProxyPrivate -@@ -250,6 +256,148 @@ - g_type_class_add_private (klass, sizeof (NetProxyPrivate)); - } - -+ -+static gboolean -+ubuntu_is_in_admin_group (int id_group) -+{ -+ gid_t groups [1024]; -+ int i, ngroups; -+ -+ ngroups = getgroups (1024, groups); -+ if (ngroups < 0) { -+ perror ("getgroups"); -+ return FALSE; -+ } -+ -+ for (i = 0; i < ngroups; ++i) { -+ if (groups[i] == id_group) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+static gboolean -+ubuntu_is_admin () -+{ -+ struct group *admin_group; -+ -+ admin_group = getgrnam ("admin"); -+ if (admin_group != NULL && ubuntu_is_in_admin_group (admin_group->gr_gid)) -+ return TRUE; -+ -+ admin_group = getgrnam ("sudo"); -+ if (admin_group != NULL && ubuntu_is_in_admin_group (admin_group->gr_gid)) -+ return TRUE; -+ -+ return FALSE; -+} -+ -+static void -+ubuntu_reset_system_proxy (GDBusProxy *proxy, const gchar *protocol) -+{ -+ GVariant *result; -+ GError *error = NULL; -+ -+ result = g_dbus_proxy_call_sync (proxy, "set_proxy", -+ g_variant_new ("(ss)", protocol, ""), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, NULL, &error); -+ if (result) -+ g_variant_unref (result); -+ else { -+ g_warning ("Error while calling set_proxy for %s protocol: %s", protocol, error->message); -+ g_error_free (error); -+ } -+} -+ -+static void -+ubuntu_set_proxy_for_protocol (GDBusProxy *proxy, const gchar *protocol, GSettings *settings) -+{ -+ GVariant *result; -+ gchar *proxy_str, *host; -+ GError *error = NULL; -+ gint port; -+ -+ host = g_settings_get_string (settings, "host"); -+ port = g_settings_get_int (settings, "port"); -+ -+ if (host && *host == '\0') { -+ ubuntu_reset_system_proxy (proxy, protocol); -+ } else { -+ proxy_str = g_strdup_printf ("%s://%s:%i/", protocol, host, port); -+ -+ result = g_dbus_proxy_call_sync (proxy, "set_proxy", -+ g_variant_new ("(ss)", protocol, proxy_str), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, NULL, &error); -+ if (result) -+ g_variant_unref (result); -+ else { -+ g_warning ("Error while calling set_proxy for %s protocol: %s", protocol, error->message); -+ g_error_free (error); -+ } -+ g_free (proxy_str); -+ } -+ -+ /* Free memory */ -+ g_free (host); -+ g_object_unref (settings); -+} -+ -+static void -+ubuntu_on_proxy_apply_system_settings (GtkButton *button, gpointer user_data) -+{ -+ GDBusConnection *bus; -+ GDBusProxy *dbus_proxy; -+ GError *error; -+ GDesktopProxyMode proxy_mode; -+ NetProxy *proxy = NET_PROXY (user_data); -+ -+ error = NULL; -+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); -+ if (!bus) { -+ g_warning ("Could not retrieve system bus: %s", error->message); -+ g_error_free (error); -+ -+ return; -+ } -+ -+ dbus_proxy = g_dbus_proxy_new_sync (bus, 0, NULL, -+ "com.ubuntu.SystemService", -+ "/", -+ "com.ubuntu.SystemService", -+ NULL, -+ &error); -+ if (!dbus_proxy) { -+ g_warning ("Could not retrieve bus object: %s", error->message); -+ g_error_free (error); -+ -+ return; -+ } -+ -+ /* Retrieve the current settings */ -+ proxy_mode = g_settings_get_enum (proxy->priv->settings, "mode"); -+ switch (proxy_mode) { -+ case G_DESKTOP_PROXY_MODE_AUTO: -+ case G_DESKTOP_PROXY_MODE_NONE: -+ ubuntu_reset_system_proxy (dbus_proxy, "http"); -+ ubuntu_reset_system_proxy (dbus_proxy, "https"); -+ ubuntu_reset_system_proxy (dbus_proxy, "ftp"); -+ ubuntu_reset_system_proxy (dbus_proxy, "socks"); -+ break; -+ case G_DESKTOP_PROXY_MODE_MANUAL: -+ ubuntu_set_proxy_for_protocol (dbus_proxy, "http", g_settings_get_child (proxy->priv->settings, "http")); -+ ubuntu_set_proxy_for_protocol (dbus_proxy, "https", g_settings_get_child (proxy->priv->settings, "https")); -+ ubuntu_set_proxy_for_protocol (dbus_proxy, "ftp", g_settings_get_child (proxy->priv->settings, "ftp")); -+ ubuntu_set_proxy_for_protocol (dbus_proxy, "socks", g_settings_get_child (proxy->priv->settings, "socks")); -+ break; -+ } -+ -+ /* Free memory */ -+ g_object_unref (dbus_proxy); -+} -+ - static void - net_proxy_init (NetProxy *proxy) - { -@@ -369,6 +517,13 @@ - "label_proxy_status")); - gtk_label_set_label (GTK_LABEL (widget), ""); - -+ /* Ubuntu button for system proxy settings */ -+ if (ubuntu_is_admin ()) { -+ g_signal_connect (G_OBJECT (gtk_builder_get_object (proxy->priv->builder, "system_proxy_button")), "clicked", -+ G_CALLBACK (ubuntu_on_proxy_apply_system_settings), proxy); -+ } else -+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, "system_proxy_button"))); -+ - /* hide the switch until we get some more detail in the mockup */ - widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, - "device_proxy_off_switch")); -Index: gnome-control-center-3.6.3/panels/network/network-proxy.ui -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/network/network-proxy.ui 2013-04-16 16:14:41.159226157 +0200 -+++ gnome-control-center-3.6.3/panels/network/network-proxy.ui 2013-04-16 16:14:41.155226157 +0200 -@@ -280,6 +280,21 @@ - - - -+ -+ Apply system wide -+ True -+ True -+ True -+ False -+ -+ -+ 0 -+ 7 -+ 3 -+ 1 -+ -+ -+ - - True - False -@@ -290,7 +305,7 @@ - - - 0 -- 7 -+ 8 - 3 - 1 - diff -Nru gnome-control-center-3.6.3/debian/patches/97_unity_power_ui.patch gnome-control-center-3.6.3/debian/patches/97_unity_power_ui.patch --- gnome-control-center-3.6.3/debian/patches/97_unity_power_ui.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/97_unity_power_ui.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -Description: When indicator-power is installed, display an extra option in the power panel. -Forwarded: not-needed - -Index: b/panels/power/cc-power-panel.c -=================================================================== ---- a/panels/power/cc-power-panel.c -+++ b/panels/power/cc-power-panel.c -@@ -39,6 +39,7 @@ - { - GSettings *lock_settings; - GSettings *gsd_settings; -+ GSettings *power_settings; - GCancellable *cancellable; - GtkBuilder *builder; - GDBusProxy *proxy; -@@ -89,6 +90,11 @@ - g_object_unref (priv->gsd_settings); - priv->gsd_settings = NULL; - } -+ if (priv->power_settings) -+ { -+ g_object_unref (priv->power_settings); -+ priv->power_settings = NULL; -+ } - if (priv->cancellable != NULL) - { - g_cancellable_cancel (priv->cancellable); -@@ -1112,6 +1118,37 @@ - - widget = WID (self->priv->builder, "vbox_power"); - gtk_widget_reparent (widget, (GtkWidget *) self); -+ -+ /* Set up Unity-specific controls */ -+ /* References: -+ * https://wiki.ubuntu.com/Power -+ * https://docs.google.com/document/d/1ILTJDiDCd25Npt2AmgzF8aOnZZECxTfM0hvsbWT2BxA/edit?pli=1#heading=h.i5lg1g344bsb -+ */ -+ // First check the schema is installed -+ GSettingsSchemaSource *schema_source = g_settings_schema_source_ref ( -+ g_settings_schema_source_get_default ()); -+ GSettingsSchema *schema = g_settings_schema_source_lookup ( -+ schema_source, -+ "com.canonical.indicator.power", -+ TRUE); -+ g_settings_schema_source_unref (schema_source); -+ -+ if (schema) -+ { -+ widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, -+ "combobox_indicator")); -+ self->priv->power_settings = g_settings_new ("com.canonical.indicator.power"); -+ g_settings_bind (self->priv->power_settings, "icon-policy", -+ widget, "active-id", G_SETTINGS_BIND_DEFAULT); -+ g_settings_schema_unref (schema); -+ } -+ else -+ { -+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "separator_indicator"))); -+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "label_indicator"))); -+ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "combobox_indicator"))); -+ } -+ - } - - void -Index: b/panels/power/power.ui -=================================================================== ---- a/panels/power/power.ui -+++ b/panels/power/power.ui -@@ -75,6 +75,28 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ When battery is present -+ present -+ -+ -+ When battery is charging/in use -+ charge -+ -+ -+ Never -+ never -+ -+ -+ - - False - False -@@ -238,6 +260,48 @@ - 3 - - -+ -+ -+ True -+ False -+ -+ -+ 0 -+ 4 -+ 4 -+ 1 -+ -+ -+ -+ -+ True -+ False -+ end -+ Show battery status in the _menu bar -+ True -+ -+ -+ 0 -+ 5 -+ -+ -+ -+ -+ True -+ False -+ liststore_indicator -+ True -+ -+ -+ -+ -+ -+ 1 -+ 5 -+ 2 -+ 1 -+ -+ - - - False -Index: b/configure.ac -=================================================================== ---- a/configure.ac -+++ b/configure.ac -@@ -94,7 +94,7 @@ - dnl Check that we meet the dependencies - dnl ============================================== - --GLIB_REQUIRED_VERSION=2.31.0 -+GLIB_REQUIRED_VERSION=2.31.2 - GTK_REQUIRED_VERSION=3.5.13 - PA_REQUIRED_VERSION=2.0 - CANBERRA_REQUIRED_VERSION=0.13 diff -Nru gnome-control-center-3.6.3/debian/patches/98_default_sound_theme.patch gnome-control-center-3.6.3/debian/patches/98_default_sound_theme.patch --- gnome-control-center-3.6.3/debian/patches/98_default_sound_theme.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/98_default_sound_theme.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# Description: the default sound theme is "ubuntu" for us -# UbuntuSpecific: yes -# -Index: b/panels/sound/gvc-sound-theme-chooser.c -=================================================================== ---- a/panels/sound/gvc-sound-theme-chooser.c -+++ b/panels/sound/gvc-sound-theme-chooser.c -@@ -67,7 +67,7 @@ - #define DEFAULT_ALERT_ID "__default" - #define CUSTOM_THEME_NAME "__custom" - #define NO_SOUNDS_THEME_NAME "__no_sounds" --#define DEFAULT_THEME "freedesktop" -+#define DEFAULT_THEME "ubuntu" - - enum { - THEME_DISPLAY_COL, diff -Nru gnome-control-center-3.6.3/debian/patches/99_add_lock-on-suspend.patch gnome-control-center-3.6.3/debian/patches/99_add_lock-on-suspend.patch --- gnome-control-center-3.6.3/debian/patches/99_add_lock-on-suspend.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/99_add_lock-on-suspend.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -Description: Add a new preference to lock the screen when the system suspends. -Author: Marc Deslauriers -Forwarded: no, likely a Ubuntu-specific preference -Bug-Ubuntu: https://bugs.launchpad.net/bugs/938076 - -Index: b/panels/screen/cc-screen-panel.c -=================================================================== ---- a/panels/screen/cc-screen-panel.c -+++ b/panels/screen/cc-screen-panel.c -@@ -540,6 +540,13 @@ - - update_lock_screen_sensitivity (self); - -+ /* bind the screen lock suspend checkbutton */ -+ widget = WID ("screen_lock_suspend_checkbutton"); -+ g_settings_bind (self->priv->lock_settings, -+ "ubuntu-lock-on-suspend", -+ widget, "active", -+ G_SETTINGS_BIND_DEFAULT); -+ - widget = WID ("screen_vbox"); - gtk_widget_reparent (widget, (GtkWidget *) self); - g_object_set (self, "valign", GTK_ALIGN_START, NULL); -Index: b/panels/screen/screen.ui -=================================================================== ---- a/panels/screen/screen.ui -+++ b/panels/screen/screen.ui -@@ -299,6 +299,31 @@ - - - -+ -+ True -+ False -+ 6 -+ -+ -+ Require my password when waking from suspend -+ False -+ True -+ True -+ -+ -+ False -+ False -+ 0 -+ -+ -+ -+ -+ False -+ False -+ 2 -+ -+ -+ - - False - True -@@ -340,7 +365,7 @@ - - True - True -- 2 -+ 3 - - - -@@ -357,7 +382,7 @@ - - True - True -- 3 -+ 4 - - - diff -Nru gnome-control-center-3.6.3/debian/patches/accounts_fix_unsetting_icon.patch gnome-control-center-3.6.3/debian/patches/accounts_fix_unsetting_icon.patch --- gnome-control-center-3.6.3/debian/patches/accounts_fix_unsetting_icon.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/accounts_fix_unsetting_icon.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# Upstream: https://bugzilla.gnome.org/show_bug.cgi?id=673841 -# Ubuntu: https://launchpad.net/bugs/978049 -# -Index: gnome-control-center-3.6.2/panels/user-accounts/um-user.c -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/user-accounts/um-user.c 2012-11-01 20:44:03.426070880 -0400 -+++ gnome-control-center-3.6.2/panels/user-accounts/um-user.c 2012-11-01 20:44:03.442070879 -0400 -@@ -730,7 +730,7 @@ - GVariant *result; - GError *error = NULL; - -- result = g_dbus_proxy_call_sync (user->proxy, "SetIconFile", g_variant_new ("(s)", icon_file), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); -+ result = g_dbus_proxy_call_sync (user->proxy, "SetIconFile", g_variant_new ("(s)", icon_file ? icon_file : ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - if (!result) { - g_warning ("SetIconFile call failed: %s", error->message); - g_error_free (error); diff -Nru gnome-control-center-3.6.3/debian/patches/classic_use_sound_indicator.patch gnome-control-center-3.6.3/debian/patches/classic_use_sound_indicator.patch --- gnome-control-center-3.6.3/debian/patches/classic_use_sound_indicator.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/classic_use_sound_indicator.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -Index: b/panels/sound/data/gnome-sound-applet.desktop.in -=================================================================== ---- a/panels/sound/data/gnome-sound-applet.desktop.in -+++ b/panels/sound/data/gnome-sound-applet.desktop.in -@@ -14,4 +14,4 @@ - #X-GNOME-Autostart-Phase=Panel - X-GNOME-Autostart-Notify=true - AutostartCondition=GNOME3 if-session gnome-fallback --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=; diff -Nru gnome-control-center-3.6.3/debian/patches/deal_with_null_ssid.patch gnome-control-center-3.6.3/debian/patches/deal_with_null_ssid.patch --- gnome-control-center-3.6.3/debian/patches/deal_with_null_ssid.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/deal_with_null_ssid.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -From: Dan Williams -Subject: Avoid crashing when SSIDs are NULL. -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/908670 -Bug: https://bugzilla.gnome.org/show_bug.cgi?id=672922 - ---- - panels/network/cc-network-panel.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -Index: gnome-control-center-3.5.2/panels/network/cc-network-panel.c -=================================================================== ---- gnome-control-center-3.5.2.orig/panels/network/cc-network-panel.c 2012-06-08 16:49:24.888332382 +1200 -+++ gnome-control-center-3.5.2/panels/network/cc-network-panel.c 2012-06-08 17:00:13.600309923 +1200 -@@ -1128,13 +1128,19 @@ - if (aps != NULL) - for (i = 0; i < aps->len; i++) { - ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i)); -+ -+ /* Hidden SSIDs don't get shown in the list */ - ssid = nm_access_point_get_ssid (ap); -+ if (!ssid) -+ continue; -+ - add_ap = TRUE; - - /* get already added list */ - for (j=0; jlen; j++) { - ap_tmp = NM_ACCESS_POINT (g_ptr_array_index (aps_unique, j)); - ssid_tmp = nm_access_point_get_ssid (ap_tmp); -+ g_assert (ssid_tmp); - - /* is this the same type and data? */ - if (nm_utils_same_ssid (ssid, ssid_tmp, TRUE)) { diff -Nru gnome-control-center-3.6.3/debian/patches/dont_download_local_image.patch gnome-control-center-3.6.3/debian/patches/dont_download_local_image.patch --- gnome-control-center-3.6.3/debian/patches/dont_download_local_image.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/dont_download_local_image.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -From 7b7f35b172e8c604aa723a3cd414088563a7d490 Mon Sep 17 00:00:00 2001 -From: Ryan Lortie -Date: Mon, 19 Mar 2012 12:55:31 -0400 -Subject: [PATCH] background: don't 'download' image files - -The code for downloading files from remote uris was being triggered in -the case of adding a background image file via the file chooser. Don't -set the 'source-url' attribute on the image in this case in order to -avoid the problem. - -https://bugzilla.gnome.org/show_bug.cgi?id=672405 ---- - panels/background/bg-pictures-source.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -Index: b/panels/background/bg-pictures-source.c -=================================================================== ---- a/panels/background/bg-pictures-source.c -+++ b/panels/background/bg-pictures-source.c -@@ -335,7 +335,7 @@ - "shading", G_DESKTOP_BACKGROUND_SHADING_SOLID, - "placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM, - NULL); -- if (source_uri != NULL) -+ if (source_uri != NULL && !g_file_is_native (file)) - g_object_set (G_OBJECT (item), "source-url", source_uri, NULL); - - g_object_set_data (G_OBJECT (file), "item", item); diff -Nru gnome-control-center-3.6.3/debian/patches/gcc_not_in_unity.patch gnome-control-center-3.6.3/debian/patches/gcc_not_in_unity.patch --- gnome-control-center-3.6.3/debian/patches/gcc_not_in_unity.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/gcc_not_in_unity.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -Index: gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 2014-03-04 19:17:38.322473754 +0100 -@@ -6,7 +6,7 @@ - Terminal=false - Type=Application - Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - StartupNotify=true - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-bluetooth -Index: gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/color/gnome-color-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in 2014-03-04 19:17:38.322473754 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=color -Index: gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/display/gnome-display-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in 2014-03-04 19:17:38.322473754 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=Screen resolution -Index: gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/info/gnome-info-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=info -Index: gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/keyboard/gnome-keyboard-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=keyboard -Index: gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/mouse/gnome-mouse-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=mouse -Index: gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/network/gnome-network-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=network -Index: gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/power/gnome-power-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;HardwareSettings --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=power -Index: gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/screen/gnome-screen-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=screen -Index: gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/universal-access/gnome-universal-access-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=Universal Access -Index: gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 2014-03-04 19:17:38.326473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=System;Settings;X-GNOME-Settings-Panel;X-GNOME-SystemSettings --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=user-accounts -Index: gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/wacom/gnome-wacom-panel.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in 2014-03-04 19:17:38.330473755 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=wacom -Index: gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/gnome-control-center.desktop.in.in 2014-03-04 19:17:38.334473755 +0100 -+++ gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in 2014-03-04 19:17:38.330473755 +0100 -@@ -6,7 +6,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;System; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=shell -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel.desktop.in.in 2012-11-05 09:38:42.000000000 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in 2014-03-04 19:19:14.274476950 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=region -Index: gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/sound/data/gnome-sound-panel.desktop.in.in 2012-11-14 12:42:44.000000000 +0100 -+++ gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in 2014-03-04 19:18:47.826476069 +0100 -@@ -7,7 +7,7 @@ - Type=Application - StartupNotify=true - Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; -+OnlyShowIn=GNOME; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center - X-GNOME-Bugzilla-Component=sound diff -Nru gnome-control-center-3.6.3/debian/patches/git-add-21_9_display.patch gnome-control-center-3.6.3/debian/patches/git-add-21_9_display.patch --- gnome-control-center-3.6.3/debian/patches/git-add-21_9_display.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-add-21_9_display.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -commit 66576dfe24f93b22146e436aea761bc5a3b547cf -Author: Stéphane Graber -Date: 2013-01-16 10:18:20 (GMT) - display: Add support for 21:9 displays - https://bugzilla.gnome.org/show_bug.cgi?id=691803 - ---- gnome-control-center-3.6.3.orig/panels/display/cc-display-panel.c -+++ gnome-control-center-3.6.3/panels/display/cc-display-panel.c -@@ -763,6 +763,9 @@ make_resolution_string (int width, int h - case 17: - aspect = "16:9"; - break; -+ case 23: -+ aspect = "21:9"; -+ break; - case 12: - aspect = "5:4"; - break; diff -Nru gnome-control-center-3.6.3/debian/patches/git_add_printer_crash.patch gnome-control-center-3.6.3/debian/patches/git_add_printer_crash.patch --- gnome-control-center-3.6.3/debian/patches/git_add_printer_crash.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_add_printer_crash.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -From 5a654556de7a85414e9ef3a465f383b9ea4357e7 Mon Sep 17 00:00:00 2001 -From: Marek Kasik -Date: Wed, 24 Apr 2013 11:03:22 +0000 -Subject: printers: Don't crash without system-config-printer - -Fix error handling in addition of new printer. - -https://bugzilla.gnome.org/show_bug.cgi?id=698642 ---- -diff --git a/panels/printers/pp-new-printer.c b/panels/printers/pp-new-printer.c -index 038a2ad..c76f1ac 100644 ---- a/panels/printers/pp-new-printer.c -+++ b/panels/printers/pp-new-printer.c -@@ -683,6 +683,7 @@ printer_add_async_scb (GObject *source_object, - GDBusConnection *bus; - GVariantBuilder array_builder; - GVariant *output; -+ gboolean cancelled = FALSE; - PPDName *ppd_item = NULL; - GError *error = NULL; - -@@ -698,15 +699,15 @@ printer_add_async_scb (GObject *source_object, - } - else - { -- if (error->domain != G_IO_ERROR || -- error->code != G_IO_ERROR_CANCELLED) -+ cancelled = g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); -+ -+ if (!cancelled) - g_warning ("%s", error->message); -- g_error_free (error); -+ -+ g_clear_error (&error); - } - -- if (!error || -- error->domain != G_IO_ERROR || -- error->code != G_IO_ERROR_CANCELLED) -+ if (!cancelled) - { - if (ppd_item == NULL || ppd_item->ppd_match_level < PPD_EXACT_MATCH) - { --- -cgit v0.9.2 diff -Nru gnome-control-center-3.6.3/debian/patches/git-background-lock-screen.patch gnome-control-center-3.6.3/debian/patches/git-background-lock-screen.patch --- gnome-control-center-3.6.3/debian/patches/git-background-lock-screen.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-background-lock-screen.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,854 +0,0 @@ -From 074f55e344c4d36fad52acadf344dae9cd7bda75 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Mon, 19 Aug 2013 19:00:48 +0000 -Subject: background: Add support for lock screen background - -https://bugzilla.gnome.org/show_bug.cgi?id=696166 ---- ---- a/panels/background/background.ui -+++ b/panels/background/background.ui -@@ -4,115 +4,286 @@ - - True - False -+ 6 -+ 6 -+ 6 -+ 6 - 10 - 12 -- 6 -- 6 -- 6 -- 6 - -- -+ - True - False -- 6 -+ 100 -+ 100 - -- -+ - True - False -- 12 -- 0 -- none - -- -- False -+ - True -- True -- True -- center -+ False -+ 12 -+ 0 -+ none - -- -- 417 -- 250 -+ - True -- False -+ True -+ True - center -- 6 -- 6 -- 6 -- 6 -- True -- True -+ -+ -+ True -+ False -+ vertical -+ -+ -+ 310 -+ 170 -+ True -+ False -+ center -+ 6 -+ 6 -+ 6 -+ 6 -+ True -+ True -+ -+ -+ False -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ Background -+ -+ -+ False -+ True -+ 1 -+ -+ -+ -+ - - - -+ -+ True -+ True -+ 0 -+ - -- -- -- True -- True -- 0 -- -- -- -- -- True -- False -- 12 - -- -+ - True - False -- center -- 2 -+ 12 - -- -+ - True - False -- slideshow-symbolic -+ center -+ 12 -+ 2 -+ -+ -+ True -+ False -+ slideshow-symbolic -+ -+ -+ False -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ -+ -+ -+ False -+ True -+ 1 -+ -+ -+ -+ -+ True -+ False -+ 0 -+ Changes throughout the day -+ -+ -+ False -+ True -+ 1 -+ -+ - - -- False -+ True - True - 0 - - -+ -+ -+ False -+ True -+ 2 -+ -+ -+ -+ -+ False -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ -+ -+ True -+ False -+ 12 -+ 0 -+ none - -- -+ - True -- False -- -+ True -+ True -+ center -+ -+ -+ True -+ False -+ vertical -+ -+ -+ 310 -+ 170 -+ True -+ False -+ center -+ 6 -+ 6 -+ 6 -+ 6 -+ True -+ True -+ -+ -+ False -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ Lock Screen -+ -+ -+ False -+ True -+ 1 -+ -+ -+ -+ - -- -- False -- True -- 1 -- - -+ -+ -+ True -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ 12 - -- -+ - True - False -- 0 -- Changes throughout the day -+ center -+ 12 -+ 2 -+ -+ -+ True -+ False -+ slideshow-symbolic -+ -+ -+ False -+ True -+ 0 -+ -+ -+ -+ -+ True -+ False -+ -+ -+ -+ False -+ True -+ 1 -+ -+ -+ -+ -+ True -+ False -+ 0 -+ Changes throughout the day -+ -+ -+ False -+ True -+ 1 -+ -+ - - -- False -+ True - True -- 1 -+ 0 - - - - -- True -+ False - True -- 0 -+ 2 - - - - - False - True -- 2 -+ 1 - - - ---- a/panels/background/cc-background-panel.c -+++ b/panels/background/cc-background-panel.c -@@ -38,6 +38,7 @@ - #include "bg-pictures-source.h" - - #define WP_PATH_ID "org.gnome.desktop.background" -+#define WP_LOCK_PATH_ID "org.gnome.desktop.screensaver" - #define WP_URI_KEY "picture-uri" - #define WP_OPTIONS_KEY "picture-options" - #define WP_SHADING_KEY "color-shading-type" -@@ -55,10 +56,12 @@ - GDBusConnection *connection; - - GSettings *settings; -+ GSettings *lock_settings; - - GnomeDesktopThumbnailFactory *thumb_factory; - - CcBackgroundItem *current_background; -+ CcBackgroundItem *current_lock_background; - - GCancellable *copy_cancellable; - GCancellable *capture_cancellable; -@@ -70,6 +73,8 @@ - }; - - #define WID(y) (GtkWidget *) gtk_builder_get_object (priv->builder, y) -+#define CURRENT_BG (settings == priv->settings ? priv->current_background : priv->current_lock_background) -+#define SAVE_PATH (settings == priv->settings ? "last-edited.xml" : "last-edited-lock.xml") - - static const char * - cc_background_panel_get_help_uri (CcPanel *panel) -@@ -88,6 +93,7 @@ - priv->spinner = NULL; - - g_clear_object (&priv->settings); -+ g_clear_object (&priv->lock_settings); - - if (priv->copy_cancellable) - { -@@ -124,6 +130,7 @@ - CcBackgroundPanelPrivate *priv = CC_BACKGROUND_PANEL (object)->priv; - - g_clear_object (&priv->current_background); -+ g_clear_object (&priv->current_lock_background); - - G_OBJECT_CLASS (cc_background_panel_parent_class)->finalize (object); - } -@@ -144,59 +151,77 @@ - - static void - update_preview (CcBackgroundPanelPrivate *priv, -+ GSettings *settings, - CcBackgroundItem *item) - { - gboolean changes_with_time; -+ CcBackgroundItem *current_background; -+ -+ current_background = CURRENT_BG; - -- if (item && priv->current_background) -+ if (item && current_background) - { -- g_object_unref (priv->current_background); -- priv->current_background = cc_background_item_copy (item); -- cc_background_item_load (priv->current_background, NULL); -+ g_object_unref (current_background); -+ current_background = cc_background_item_copy (item); -+ if (settings == priv->settings) -+ priv->current_background = current_background; -+ else -+ priv->current_lock_background = current_background; -+ cc_background_item_load (current_background, NULL); - } - - changes_with_time = FALSE; - -- if (priv->current_background) -+ if (current_background) - { -- changes_with_time = cc_background_item_changes_with_time (priv->current_background); -+ changes_with_time = cc_background_item_changes_with_time (current_background); - } - -- gtk_widget_set_visible (WID ("slide_image"), changes_with_time); -- gtk_widget_set_visible (WID ("slide-label"), changes_with_time); -+ if (settings == priv->settings) -+ { -+ gtk_widget_set_visible (WID ("slide_image"), changes_with_time); -+ gtk_widget_set_visible (WID ("slide-label"), changes_with_time); -+ -+ gtk_widget_queue_draw (WID ("background-desktop-drawingarea")); -+ } -+ else -+ { -+ gtk_widget_set_visible (WID ("slide_image1"), changes_with_time); -+ gtk_widget_set_visible (WID ("slide-label1"), changes_with_time); - -- gtk_widget_queue_draw (WID ("background-desktop-drawingarea")); -+ gtk_widget_queue_draw (WID ("background-lock-drawingarea")); -+ } - } - - static char * --get_save_path (void) -+get_save_path (const char *filename) - { - return g_build_filename (g_get_user_config_dir (), - "gnome-control-center", - "backgrounds", -- "last-edited.xml", -+ filename, - NULL); - } - - static void --update_display_preview (CcBackgroundPanel *panel) -+update_display_preview (CcBackgroundPanel *panel, -+ GtkWidget *widget, -+ CcBackgroundItem *current_background) - { - CcBackgroundPanelPrivate *priv = panel->priv; -- GtkWidget *widget; - GtkAllocation allocation; -- const gint preview_width = 416; -- const gint preview_height = 248; -+ const gint preview_width = 309; -+ const gint preview_height = 168; - GdkPixbuf *pixbuf; - GIcon *icon; - cairo_t *cr; - -- widget = WID ("background-desktop-drawingarea"); - gtk_widget_get_allocation (widget, &allocation); - -- if (!priv->current_background) -+ if (!current_background) - return; - -- icon = cc_background_item_get_frame_thumbnail (priv->current_background, -+ icon = cc_background_item_get_frame_thumbnail (current_background, - priv->thumb_factory, - preview_width, - preview_height, -@@ -211,11 +236,14 @@ - g_object_unref (pixbuf); - - pixbuf = NULL; -- if (panel->priv->display_screenshot != NULL) -- pixbuf = gdk_pixbuf_scale_simple (panel->priv->display_screenshot, -- preview_width, -- preview_height, -- GDK_INTERP_BILINEAR); -+ if (current_background == priv->current_background && -+ panel->priv->display_screenshot != NULL) -+ { -+ pixbuf = gdk_pixbuf_scale_simple (panel->priv->display_screenshot, -+ preview_width, -+ preview_height, -+ GDK_INTERP_BILINEAR); -+ } - - if (pixbuf) - { -@@ -260,6 +288,7 @@ - error->message); - g_error_free (error); - /* fallback? */ -+ priv = panel->priv; - goto out; - } - -@@ -307,7 +336,7 @@ - cairo_surface_destroy (surface); - - out: -- update_display_preview (panel); -+ update_display_preview (panel, WID ("background-desktop-drawingarea"), priv->current_background); - } - - static void -@@ -356,6 +385,7 @@ - cairo_t *cr, - CcBackgroundPanel *panel) - { -+ CcBackgroundPanelPrivate *priv = panel->priv; - /* we have another shot in flight or an existing cache */ - if (panel->priv->display_screenshot == NULL - && panel->priv->screenshot_path == NULL) -@@ -368,13 +398,24 @@ - get_screenshot_async (panel, &rect); - } - else -- update_display_preview (panel); -+ update_display_preview (panel, widget, priv->current_background); -+ -+ return TRUE; -+} - -+static gboolean -+on_lock_preview_draw (GtkWidget *widget, -+ cairo_t *cr, -+ CcBackgroundPanel *panel) -+{ -+ CcBackgroundPanelPrivate *priv = panel->priv; -+ update_display_preview (panel, widget, priv->current_lock_background); - return TRUE; - } - - static void --reload_current_bg (CcBackgroundPanel *self) -+reload_current_bg (CcBackgroundPanel *self, -+ GSettings *settings) - { - CcBackgroundPanelPrivate *priv; - CcBackgroundItem *saved, *configured; -@@ -383,12 +424,12 @@ - priv = self->priv; - - /* Load the saved configuration */ -- uri = get_save_path (); -+ uri = get_save_path (SAVE_PATH); - saved = cc_background_xml_get_item (uri); - g_free (uri); - - /* initalise the current background information from settings */ -- uri = g_settings_get_string (priv->settings, WP_URI_KEY); -+ uri = g_settings_get_string (settings, WP_URI_KEY); - if (uri && *uri == '\0') - { - g_free (uri); -@@ -404,12 +445,12 @@ - configured = cc_background_item_new (uri); - g_free (uri); - -- pcolor = g_settings_get_string (priv->settings, WP_PCOLOR_KEY); -- scolor = g_settings_get_string (priv->settings, WP_SCOLOR_KEY); -+ pcolor = g_settings_get_string (settings, WP_PCOLOR_KEY); -+ scolor = g_settings_get_string (settings, WP_SCOLOR_KEY); - g_object_set (G_OBJECT (configured), - "name", _("Current background"), -- "placement", g_settings_get_enum (priv->settings, WP_OPTIONS_KEY), -- "shading", g_settings_get_enum (priv->settings, WP_SHADING_KEY), -+ "placement", g_settings_get_enum (settings, WP_OPTIONS_KEY), -+ "shading", g_settings_get_enum (settings, WP_SHADING_KEY), - "primary-color", pcolor, - "secondary-color", scolor, - NULL); -@@ -433,9 +474,17 @@ - if (saved != NULL) - g_object_unref (saved); - -- g_clear_object (&priv->current_background); -- priv->current_background = configured; -- cc_background_item_load (priv->current_background, NULL); -+ if (settings == priv->settings) -+ { -+ g_clear_object (&priv->current_background); -+ priv->current_background = configured; -+ } -+ else -+ { -+ g_clear_object (&priv->current_lock_background); -+ priv->current_lock_background = configured; -+ } -+ cc_background_item_load (configured, NULL); - } - - static gboolean -@@ -466,6 +515,8 @@ - CcBackgroundPanel *panel = (CcBackgroundPanel *) pointer; - CcBackgroundPanelPrivate *priv = panel->priv; - CcBackgroundItem *item; -+ CcBackgroundItem *current_background; -+ GSettings *settings; - - if (!g_file_copy_finish (G_FILE (source_object), result, &err)) - { -@@ -477,8 +528,10 @@ - g_error_free (err); - } - item = g_object_get_data (source_object, "item"); -+ settings = g_object_get_data (source_object, "settings"); -+ current_background = CURRENT_BG; - -- g_settings_apply (priv->settings); -+ g_settings_apply (settings); - - /* the panel may have been destroyed before the callback is run, so be sure - * to check the widgets are not NULL */ -@@ -489,19 +542,19 @@ - priv->spinner = NULL; - } - -- if (priv->current_background) -- cc_background_item_load (priv->current_background, NULL); -+ if (current_background) -+ cc_background_item_load (current_background, NULL); - - if (priv->builder) - { - char *filename; - -- update_preview (priv, item); -+ update_preview (priv, settings, item); - - /* Save the source XML if there is one */ -- filename = get_save_path (); -+ filename = get_save_path (SAVE_PATH); - if (create_save_dir ()) -- cc_background_xml_save (priv->current_background, filename); -+ cc_background_xml_save (current_background, filename); - } - - /* remove the reference taken when the copy was set up */ -@@ -510,6 +563,7 @@ - - static void - set_background (CcBackgroundPanel *panel, -+ GSettings *settings, - CcBackgroundItem *item) - { - CcBackgroundPanelPrivate *priv = panel->priv; -@@ -527,8 +581,8 @@ - - if ((flags & CC_BACKGROUND_ITEM_HAS_URI) && uri == NULL) - { -- g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE); -- g_settings_set_string (priv->settings, WP_URI_KEY, ""); -+ g_settings_set_enum (settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE); -+ g_settings_set_string (settings, WP_URI_KEY, ""); - } - else if (cc_background_item_get_source_url (item) != NULL && - cc_background_item_get_needs_download (item)) -@@ -585,6 +639,7 @@ - * finished */ - g_object_ref (panel); - g_object_set_data_full (G_OBJECT (source), "item", g_object_ref (item), g_object_unref); -+ g_object_set_data (G_OBJECT (source), "settings", settings); - g_file_copy_async (source, dest, G_FILE_COPY_OVERWRITE, - G_PRIORITY_DEFAULT, priv->copy_cancellable, - NULL, NULL, -@@ -593,7 +648,7 @@ - dest_uri = g_file_get_uri (dest); - g_object_unref (dest); - -- g_settings_set_string (priv->settings, WP_URI_KEY, dest_uri); -+ g_settings_set_string (settings, WP_URI_KEY, dest_uri); - g_object_set (G_OBJECT (item), - "uri", dest_uri, - "needs-download", FALSE, -@@ -607,37 +662,37 @@ - } - else - { -- g_settings_set_string (priv->settings, WP_URI_KEY, uri); -+ g_settings_set_string (settings, WP_URI_KEY, uri); - } - - /* Also set the placement if we have a URI and the previous value was none */ - if (flags & CC_BACKGROUND_ITEM_HAS_PLACEMENT) - { -- g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); -+ g_settings_set_enum (settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); - } - else if (uri != NULL) - { -- style = g_settings_get_enum (priv->settings, WP_OPTIONS_KEY); -+ style = g_settings_get_enum (settings, WP_OPTIONS_KEY); - if (style == G_DESKTOP_BACKGROUND_STYLE_NONE) -- g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); -+ g_settings_set_enum (settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); - } - - if (flags & CC_BACKGROUND_ITEM_HAS_SHADING) -- g_settings_set_enum (priv->settings, WP_SHADING_KEY, cc_background_item_get_shading (item)); -+ g_settings_set_enum (settings, WP_SHADING_KEY, cc_background_item_get_shading (item)); - -- g_settings_set_string (priv->settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item)); -- g_settings_set_string (priv->settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item)); -+ g_settings_set_string (settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item)); -+ g_settings_set_string (settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item)); - - /* update the preview information */ - if (save_settings != FALSE) - { - /* Apply all changes */ -- g_settings_apply (priv->settings); -+ g_settings_apply (settings); - - /* Save the source XML if there is one */ -- filename = get_save_path (); -+ filename = get_save_path (SAVE_PATH); - if (create_save_dir ()) -- cc_background_xml_save (priv->current_background, filename); -+ cc_background_xml_save (CURRENT_BG, filename); - } - } - -@@ -653,7 +708,7 @@ - item = cc_background_chooser_dialog_get_item (CC_BACKGROUND_CHOOSER_DIALOG (dialog)); - if (item != NULL) - { -- set_background (self, item); -+ set_background (self, g_object_get_data (G_OBJECT (dialog), "settings"), item); - g_object_unref (item); - } - } -@@ -662,13 +717,14 @@ - } - - static void --on_background_button_clicked (GtkButton *button, -- CcBackgroundPanel *self) -+launch_chooser (CcBackgroundPanel *self, -+ GSettings *settings) - { - CcBackgroundPanelPrivate *priv = self->priv; - GtkWidget *dialog; - - dialog = cc_background_chooser_dialog_new (); -+ g_object_set_data (G_OBJECT (dialog), "settings", settings); - gtk_window_set_transient_for (GTK_WINDOW (dialog), - GTK_WINDOW (gtk_widget_get_toplevel (WID ("background-panel")))); - gtk_widget_show (dialog); -@@ -676,12 +732,26 @@ - } - - static void -+on_background_button_clicked (GtkButton *button, -+ CcBackgroundPanel *self) -+{ -+ launch_chooser (self, self->priv->settings); -+} -+ -+static void -+on_lock_button_clicked (GtkButton *button, -+ CcBackgroundPanel *self) -+{ -+ launch_chooser (self, self->priv->lock_settings); -+} -+ -+static void - on_settings_changed (GSettings *settings, - gchar *key, - CcBackgroundPanel *self) - { -- reload_current_bg (self); -- update_preview (self->priv, NULL); -+ reload_current_bg (self, settings); -+ update_preview (self->priv, settings, NULL); - } - - static void -@@ -711,6 +781,9 @@ - priv->settings = g_settings_new (WP_PATH_ID); - g_settings_delay (priv->settings); - -+ priv->lock_settings = g_settings_new (WP_LOCK_PATH_ID); -+ g_settings_delay (priv->lock_settings); -+ - /* add the top level widget */ - widget = WID ("background-panel"); - -@@ -719,21 +792,30 @@ - - /* setup preview area */ - widget = WID ("background-desktop-drawingarea"); -- g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), -- self); -+ g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), self); -+ widget = WID ("background-lock-drawingarea"); -+ g_signal_connect (widget, "draw", G_CALLBACK (on_lock_preview_draw), self); - - priv->copy_cancellable = g_cancellable_new (); - priv->capture_cancellable = g_cancellable_new (); - - priv->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); - -- reload_current_bg (self); -- update_preview (priv, NULL); -+ /* Load the backgrounds */ -+ reload_current_bg (self, priv->settings); -+ update_preview (priv, priv->settings, NULL); -+ reload_current_bg (self, priv->lock_settings); -+ update_preview (priv, priv->lock_settings, NULL); - -+ /* Background settings */ - g_signal_connect (priv->settings, "changed", G_CALLBACK (on_settings_changed), self); -+ g_signal_connect (priv->lock_settings, "changed", G_CALLBACK (on_settings_changed), self); - -+ /* Background buttons */ - widget = WID ("background-set-button"); - g_signal_connect (widget, "clicked", G_CALLBACK (on_background_button_clicked), self); -+ widget = WID ("background-lock-set-button"); -+ g_signal_connect (widget, "clicked", G_CALLBACK (on_lock_button_clicked), self); - } - - void diff -Nru gnome-control-center-3.6.3/debian/patches/git-background-remove-unused-widget.patch gnome-control-center-3.6.3/debian/patches/git-background-remove-unused-widget.patch --- gnome-control-center-3.6.3/debian/patches/git-background-remove-unused-widget.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-background-remove-unused-widget.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -commit ea16cadce90fda067b6cba6cc831ba1ecb5adfa7 -Author: Bastien Nocera -Date: Mon Aug 19 20:55:29 2013 +0200 - - background: Remove unused "lock" preview widgets - - https://bugzilla.gnome.org/show_bug.cgi?id=696166 - ---- a/panels/background/background.ui -+++ b/panels/background/background.ui -@@ -6,6 +6,10 @@ - False - 10 - 12 -+ 6 -+ 6 -+ 6 -+ 6 - - - True -@@ -26,48 +30,18 @@ - True - center - -- -+ -+ 417 -+ 250 - True - False -+ center -+ 6 -+ 6 -+ 6 -+ 6 - True -- 18 -- -- -- 417 -- 250 -- True -- False -- center -- 6 -- 6 -- 6 -- 6 -- True -- True -- -- -- True -- True -- 0 -- -- -- -- -- False -- True -- center -- 6 -- 6 -- 6 -- True -- True -- -- -- True -- True -- 1 -- -- -+ True - - - -@@ -103,11 +77,10 @@ - - - -- -+ - True - False -- 0 -- Changes throughout the day -+ - - - False -@@ -116,10 +89,11 @@ - - - -- -+ - True - False -- -+ 0 -+ Changes throughout the day - - - False -@@ -196,8 +170,6 @@ - - vertical - -- -- - - - diff -Nru gnome-control-center-3.6.3/debian/patches/git_drop_ibus_engine_whitelist.patch gnome-control-center-3.6.3/debian/patches/git_drop_ibus_engine_whitelist.patch --- gnome-control-center-3.6.3/debian/patches/git_drop_ibus_engine_whitelist.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_drop_ibus_engine_whitelist.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -From c87d5883787c8727fcdd4ae0d61d59a89b5d4813 Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Sat, 09 Feb 2013 02:17:42 +0000 -Subject: region: Remove the IBus engines whitelist - -And just blacklist IBus' "xkb:" engines which basically duplicate all -the XKB layouts. - -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-input.c 2013-09-14 10:19:07.811746123 -0400 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c 2013-09-14 10:21:59.727738932 -0400 -@@ -87,218 +87,6 @@ - static GCancellable *ibus_cancellable = NULL; - static guint shell_name_watch_id = 0; - --static const gchar *supported_ibus_engines[] = { -- /* Simplified Chinese */ -- "pinyin", -- "bopomofo", -- "wubi", -- "erbi", -- /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ -- "libpinyin", -- "libbopomofo", -- -- /* Traditional Chinese */ -- /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ -- "chewing", -- "cangjie5", -- "cangjie3", -- "quick5", -- "quick3", -- "stroke5", -- -- /* Japanese */ -- "anthy", -- "mozc-jp", -- "skk", -- -- /* Korean */ -- "hangul", -- -- /* Thai */ -- "m17n:th:kesmanee", -- "m17n:th:pattachote", -- "m17n:th:tis820", -- -- /* Vietnamese */ -- "m17n:vi:tcvn", -- "m17n:vi:telex", -- "m17n:vi:viqr", -- "m17n:vi:vni", -- "Unikey", -- -- /* Sinhala */ -- "m17n:si:wijesekera", -- "m17n:si:phonetic-dynamic", -- "m17n:si:trans", -- "sayura", -- -- /* Indic */ -- /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ -- -- /* Assamese */ -- "m17n:as:phonetic", -- "m17n:as:inscript", -- "m17n:as:itrans", -- -- /* Bengali */ -- "m17n:bn:inscript", -- "m17n:bn:itrans", -- "m17n:bn:probhat", -- -- /* Gujarati */ -- "m17n:gu:inscript", -- "m17n:gu:itrans", -- "m17n:gu:phonetic", -- -- /* Hindi */ -- "m17n:hi:inscript", -- "m17n:hi:itrans", -- "m17n:hi:phonetic", -- "m17n:hi:remington", -- "m17n:hi:typewriter", -- "m17n:hi:vedmata", -- -- /* Kannada */ -- "m17n:kn:kgp", -- "m17n:kn:inscript", -- "m17n:kn:itrans", -- -- /* Kashmiri */ -- "m17n:ks:inscript", -- -- /* Maithili */ -- "m17n:mai:inscript", -- -- /* Malayalam */ -- "m17n:ml:inscript", -- "m17n:ml:itrans", -- "m17n:ml:mozhi", -- "m17n:ml:swanalekha", -- -- /* Marathi */ -- "m17n:mr:inscript", -- "m17n:mr:itrans", -- "m17n:mr:phonetic", -- -- /* Nepali */ -- "m17n:ne:rom", -- "m17n:ne:trad", -- -- /* Oriya */ -- "m17n:or:inscript", -- "m17n:or:itrans", -- "m17n:or:phonetic", -- -- /* Punjabi */ -- "m17n:pa:inscript", -- "m17n:pa:itrans", -- "m17n:pa:phonetic", -- "m17n:pa:jhelum", -- -- /* Sanskrit */ -- "m17n:sa:harvard-kyoto", -- -- /* Sindhi */ -- "m17n:sd:inscript", -- -- /* Tamil */ -- "m17n:ta:tamil99", -- "m17n:ta:inscript", -- "m17n:ta:itrans", -- "m17n:ta:phonetic", -- "m17n:ta:lk-renganathan", -- "m17n:ta:vutam", -- "m17n:ta:typewriter", -- -- /* Telugu */ -- "m17n:te:inscript", -- "m17n:te:apple", -- "m17n:te:pothana", -- "m17n:te:rts", -- -- /* Urdu */ -- "m17n:ur:phonetic", -- -- /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ -- "m17n:as:inscript2", -- "m17n:bn:inscript2", -- "m17n:brx:inscript2-deva", -- "m17n:doi:inscript2-deva", -- "m17n:gu:inscript2", -- "m17n:hi:inscript2", -- "m17n:kn:inscript2", -- "m17n:kok:inscript2-deva", -- "m17n:mai:inscript2", -- "m17n:ml:inscript2", -- "m17n:mni:inscript2-beng", -- "m17n:mni:inscript2-mtei", -- "m17n:mr:inscript2", -- "m17n:ne:inscript2-deva", -- "m17n:or:inscript2", -- "m17n:pa:inscript2-guru", -- "m17n:sa:inscript2", -- "m17n:sat:inscript2-deva", -- "m17n:sat:inscript2-olck", -- "m17n:sd:inscript2-deva", -- "m17n:ta:inscript2", -- "m17n:te:inscript2", -- -- /* No corresponding XKB map available for the languages */ -- -- /* Chinese Yi */ -- "m17n:ii:phonetic", -- -- /* Tai-Viet */ -- "m17n:tai:sonla", -- -- /* Kazakh in Arabic script */ -- "m17n:kk:arabic", -- -- /* Yiddish */ -- "m17n:yi:yivo", -- -- /* Canadian Aboriginal languages */ -- "m17n:ath:phonetic", -- "m17n:bla:phonetic", -- "m17n:cr:western", -- "m17n:iu:phonetic", -- "m17n:nsk:phonetic", -- "m17n:oj:phonetic", -- -- /* Non-trivial engines, like transliteration-based instead of -- keymap-based. Confirmation needed that the engines below are -- actually used by local language users. */ -- -- /* Tibetan */ -- "m17n:bo:ewts", -- "m17n:bo:tcrc", -- "m17n:bo:wylie", -- -- /* Esperanto */ -- "m17n:eo:h-f", -- "m17n:eo:h", -- "m17n:eo:plena", -- "m17n:eo:q", -- "m17n:eo:vi", -- "m17n:eo:x", -- -- /* Amharic */ -- "m17n:am:sera", -- -- /* Russian */ -- "m17n:ru:translit", -- -- /* Classical Greek */ -- "m17n:grc:mizuochi", -- -- /* Lao */ -- "m17n:lo:lrt", -- -- /* Postfix modifier input methods */ -- "m17n:da:post", -- "m17n:sv:post", -- NULL --}; - #endif /* HAVE_IBUS */ - - static void populate_model (GtkListStore *store, -@@ -475,10 +263,10 @@ - IBusEngineDesc *engine = l->data; - const gchar *engine_id = ibus_engine_desc_get_name (engine); - -- if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) -- g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); -- else -+ if (g_str_has_prefix (engine_id, "xkb:")) - g_object_unref (engine); -+ else -+ g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); - } - g_list_free (list); - diff -Nru gnome-control-center-3.6.3/debian/patches/git-fix-background-panel-crash.patch gnome-control-center-3.6.3/debian/patches/git-fix-background-panel-crash.patch --- gnome-control-center-3.6.3/debian/patches/git-fix-background-panel-crash.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-fix-background-panel-crash.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -From cd2495787209cb11492e86ecfbfb1f5505ac4240 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Tue, 26 Mar 2013 14:43:39 +0000 -Subject: background: Fix handling of cancellation in async calls - -A few of the async calls were still handling the user_data before -checking that it was still valid (eg. the operation was not cancelled), -and also printing warnings when the error was a cancellation. ---- ---- a/panels/background/bg-pictures-source.c -+++ b/panels/background/bg-pictures-source.c -@@ -413,7 +413,7 @@ - GAsyncResult *res, - gpointer user_data) - { -- BgPicturesSource *bg_source = BG_PICTURES_SOURCE (user_data); -+ BgPicturesSource *bg_source; - GList *files, *l; - GError *err = NULL; - GFile *parent; -@@ -423,7 +423,8 @@ - - if (err) - { -- g_warning ("Could not get pictures file information: %s", err->message); -+ if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) -+ g_warning ("Could not get pictures file information: %s", err->message); - g_error_free (err); - - g_list_foreach (files, (GFunc) g_object_unref, NULL); -@@ -431,6 +432,8 @@ - return; - } - -+ bg_source = BG_PICTURES_SOURCE (user_data); -+ - parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); - - /* iterate over the available files */ -@@ -453,7 +456,7 @@ - GAsyncResult *res, - gpointer user_data) - { -- BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (user_data)->priv; -+ BgPicturesSourcePrivate *priv; - GFileEnumerator *enumerator; - GError *err = NULL; - -@@ -461,12 +464,15 @@ - - if (err) - { -- if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) == FALSE) -+ if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && -+ !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Could not fill pictures source: %s", err->message); - g_error_free (err); - return; - } - -+ priv = BG_PICTURES_SOURCE (user_data)->priv; -+ - /* get the files */ - g_file_enumerator_next_files_async (enumerator, - G_MAXINT, diff -Nru gnome-control-center-3.6.3/debian/patches/git_hide_unavailable_layout_settings_btn.patch gnome-control-center-3.6.3/debian/patches/git_hide_unavailable_layout_settings_btn.patch --- gnome-control-center-3.6.3/debian/patches/git_hide_unavailable_layout_settings_btn.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_hide_unavailable_layout_settings_btn.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -From 29e0f0b28a52db83b7d4e7fb7e8ebcd4995f4c3b Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Mon, 11 Feb 2013 18:07:06 +0000 -Subject: region: Show/hide IBus sources config button - -Instead of just making it sensitive/unsensitive. Quoting from the bug -report: - -The problem is that it isn't clear to the user why the settings button is -insensitive for keyboard layouts - they'll be asking "why can't I ever use the -settings?" - -https://bugzilla.gnome.org/show_bug.cgi?id=692006 - -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-input.c 2013-09-11 10:27:26.979533097 -0400 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c 2013-09-11 10:33:09.507518772 -0400 -@@ -1104,7 +1104,7 @@ - gtk_widget_set_sensitive (show_button, index >= 0); - gtk_widget_set_sensitive (up_button, index > 0); - gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); -- gtk_widget_set_sensitive (settings_button, settings_sensitive); -+ gtk_widget_set_visible (settings_button, settings_sensitive); - } - - static void diff -Nru gnome-control-center-3.6.3/debian/patches/git_iconview_columns.patch gnome-control-center-3.6.3/debian/patches/git_iconview_columns.patch --- gnome-control-center-3.6.3/debian/patches/git_iconview_columns.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_iconview_columns.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -# Description: git patch, updated for our layout -diff --git a/shell/cc-shell-category-view.c b/shell/cc-shell-category-view.c -index 4b05d8c..d7094ab 100644 ---- a/shell/cc-shell-category-view.c -+++ b/shell/cc-shell-category-view.c -@@ -138,6 +138,7 @@ cc_shell_category_view_constructed (GObject *object) - gtk_icon_view_set_text_column (GTK_ICON_VIEW (iconview), COL_NAME); - gtk_icon_view_set_item_width (GTK_ICON_VIEW (iconview), 100); - cc_shell_item_view_update_cells (CC_SHELL_ITEM_VIEW (iconview)); -+ gtk_icon_view_set_columns (GTK_ICON_VIEW (iconview), 7); - - /* create the header if required */ - if (priv->name) --- -cgit v0.9.2 - diff -Nru gnome-control-center-3.6.3/debian/patches/git_keyboard_grp_xkb_option.patch gnome-control-center-3.6.3/debian/patches/git_keyboard_grp_xkb_option.patch --- gnome-control-center-3.6.3/debian/patches/git_keyboard_grp_xkb_option.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_keyboard_grp_xkb_option.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -From 5b98213b04627f57c55d54b10f03351c9381ccc9 Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Mon, 1 Apr 2013 20:22:16 +0200 -Subject: [PATCH] keyboard: Add the XKB option for the input source switch - shortcut - -Mutter now uses the "grp" XKB option to implement a special -modifiers-only shortcut use by gnome-shell to switch input sources. - -https://bugzilla.gnome.org/show_bug.cgi?id=700346 ---- - panels/keyboard/cc-keyboard-option.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/panels/keyboard/cc-keyboard-option.c b/panels/keyboard/cc-keyboard-option.c -index 33cb415..7a94f66 100644 ---- a/panels/keyboard/cc-keyboard-option.c -+++ b/panels/keyboard/cc-keyboard-option.c -@@ -39,6 +39,7 @@ - - #define XKB_OPTION_GROUP_LVL3 "lv3" - #define XKB_OPTION_GROUP_COMP "Compose key" -+#define XKB_OPTION_GROUP_GRP "grp" - - enum - { -@@ -97,6 +98,32 @@ static const gchar *xkb_option_comp_whitelist[] = { - NULL - }; - -+/* This list must be kept in sync with what mutter is able to -+ * handle. */ -+static const gchar *xkb_option_grp_whitelist[] = { -+ "grp:toggle", -+ "grp:lalt_toggle", -+ "grp:lwin_toggle", -+ "grp:rwin_toggle", -+ "grp:lshift_toggle", -+ "grp:rshift_toggle", -+ "grp:lctrl_toggle", -+ "grp:rctrl_toggle", -+ "grp:sclk_toggle", -+ "grp:menu_toggle", -+ "grp:caps_toggle", -+ "grp:shift_caps_toggle", -+ "grp:alt_caps_toggle", -+ "grp:alt_space_toggle", -+ "grp:ctrl_shift_toggle", -+ "grp:lctrl_lshift_toggle", -+ "grp:rctrl_rshift_toggle", -+ "grp:ctrl_alt_toggle", -+ "grp:alt_shift_toggle", -+ "grp:lalt_lshift_toggle", -+ NULL -+}; -+ - static GList *objects_list = NULL; - - GType cc_keyboard_option_get_type (void); -@@ -233,6 +260,8 @@ cc_keyboard_option_constructed (GObject *object) - self->whitelist = xkb_option_lvl3_whitelist; - else if (g_str_equal (self->group, XKB_OPTION_GROUP_COMP)) - self->whitelist = xkb_option_comp_whitelist; -+ else if (g_str_equal (self->group, XKB_OPTION_GROUP_GRP)) -+ self->whitelist = xkb_option_grp_whitelist; - else - g_assert_not_reached (); - -@@ -328,6 +357,11 @@ cc_keyboard_option_get_all (void) - "group", XKB_OPTION_GROUP_COMP, - "description", _("Compose Key"), - NULL)); -+ objects_list = g_list_prepend (objects_list, -+ g_object_new (CC_TYPE_KEYBOARD_OPTION, -+ "group", XKB_OPTION_GROUP_GRP, -+ "description", _("Modifiers-only switch to next source"), -+ NULL)); - return objects_list; - } - --- -1.9.1 - diff -Nru gnome-control-center-3.6.3/debian/patches/git_keyboard_update_input_switch.patch gnome-control-center-3.6.3/debian/patches/git_keyboard_update_input_switch.patch --- gnome-control-center-3.6.3/debian/patches/git_keyboard_update_input_switch.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_keyboard_update_input_switch.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -From 4fbf1da650224fa2dda989b8c2935a4267c8e9cc Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Tue, 18 Dec 2012 16:44:34 +0000 -Subject: keyboard: Update for the input source switching keybindings move - -These are now provided by gsettings-desktop-schemas. ---- -diff --git a/panels/keyboard/01-input-sources.xml.in b/panels/keyboard/01-input-sources.xml.in -index b3c4268..2877c48 100644 ---- a/panels/keyboard/01-input-sources.xml.in -+++ b/panels/keyboard/01-input-sources.xml.in -@@ -1,6 +1,6 @@ - - - - -Date: Wed, 21 Nov 2012 21:13:44 +0000 -Subject: display: Move GnomeRRLabeler here - -And rename to CcRRLabeler. ---- -Index: gnome-control-center-3.6.3/panels/display/Makefile.am -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/display/Makefile.am 2014-02-26 19:03:16.059681370 +0100 -+++ gnome-control-center-3.6.3/panels/display/Makefile.am 2014-02-26 19:03:16.047681370 +0100 -@@ -19,6 +19,8 @@ - display-module.c \ - cc-display-panel.c \ - cc-display-panel.h \ -+ cc-rr-labeler.c \ -+ cc-rr-labeler.h \ - scrollarea.c \ - scrollarea.h \ - $(MARSHALFILES) -Index: gnome-control-center-3.6.3/panels/display/cc-display-panel.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/display/cc-display-panel.c 2014-02-26 19:03:16.059681370 +0100 -+++ gnome-control-center-3.6.3/panels/display/cc-display-panel.c 2014-02-26 19:03:16.051681370 +0100 -@@ -31,12 +31,13 @@ - #define GNOME_DESKTOP_USE_UNSTABLE_API - #include - #include --#include - #include - #include - #include - #include - -+#include "cc-rr-labeler.h" -+ - CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) - - #define DISPLAY_PANEL_PRIVATE(o) \ -@@ -75,7 +76,7 @@ - { - GnomeRRScreen *screen; - GnomeRRConfig *current_configuration; -- GnomeRRLabeler *labeler; -+ CcRRLabeler *labeler; - GnomeRROutputInfo *current_output; - - GSettings *clock_settings; -@@ -196,7 +197,7 @@ - self->priv->focus_id); - } - -- gnome_rr_labeler_hide (self->priv->labeler); -+ cc_rr_labeler_hide (self->priv->labeler); - g_object_unref (self->priv->labeler); - - G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); -@@ -289,13 +290,13 @@ - self->priv->current_output = NULL; - - if (self->priv->labeler) { -- gnome_rr_labeler_hide (self->priv->labeler); -+ cc_rr_labeler_hide (self->priv->labeler); - g_object_unref (self->priv->labeler); - } - -- self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); -+ self->priv->labeler = cc_rr_labeler_new (self->priv->current_configuration); - if (gtk_widget_has_focus (self->priv->panel)) -- gnome_rr_labeler_show (self->priv->labeler); -+ cc_rr_labeler_show (self->priv->labeler); - - select_current_output_from_dialog_position (self); - -@@ -673,7 +674,7 @@ - tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); - - str = g_strdup_printf ("%s", tmp); -- gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); -+ cc_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); - use_color = TRUE; - g_free (tmp); - } -@@ -2073,7 +2074,7 @@ - cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); - cairo_clip_preserve (cr); - -- gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); -+ cc_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); - r = output_color.red; - g = output_color.green; - b = output_color.blue; -@@ -2581,9 +2582,9 @@ - if (self->priv->labeler == NULL) - return; - if (gtk_window_has_toplevel_focus (window)) -- gnome_rr_labeler_show (self->priv->labeler); -+ cc_rr_labeler_show (self->priv->labeler); - else -- gnome_rr_labeler_hide (self->priv->labeler); -+ cc_rr_labeler_hide (self->priv->labeler); - } - - static void -@@ -2673,7 +2674,7 @@ - int monitor_width = 30; - int monitor_height = 15; - -- gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); -+ cc_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); - - cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); - cr = cairo_create (cairo_surface); -Index: gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c 2014-02-26 19:03:16.051681370 +0100 -@@ -0,0 +1,601 @@ -+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- -+ * -+ * cc-rr-labeler.c - Utility to label monitors to identify them -+ * while they are being configured. -+ * -+ * Copyright 2008, Novell, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome 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 -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ * Author: Federico Mena-Quintero -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "cc-rr-labeler.h" -+ -+struct _CcRRLabelerPrivate { -+ GnomeRRConfig *config; -+ -+ int num_outputs; -+ -+ GdkRGBA *palette; -+ GtkWidget **windows; -+ -+ GdkScreen *screen; -+ Atom workarea_atom; -+}; -+ -+enum { -+ PROP_0, -+ PROP_CONFIG, -+ PROP_LAST -+}; -+ -+G_DEFINE_TYPE (CcRRLabeler, cc_rr_labeler, G_TYPE_OBJECT); -+ -+static void cc_rr_labeler_finalize (GObject *object); -+static void setup_from_config (CcRRLabeler *labeler); -+ -+static GdkFilterReturn -+screen_xevent_filter (GdkXEvent *xevent, -+ GdkEvent *event, -+ CcRRLabeler *labeler) -+{ -+ XEvent *xev; -+ -+ xev = (XEvent *) xevent; -+ -+ if (xev->type == PropertyNotify && -+ xev->xproperty.atom == labeler->priv->workarea_atom) { -+ /* update label positions */ -+ if (labeler->priv->windows != NULL) { -+ cc_rr_labeler_hide (labeler); -+ cc_rr_labeler_show (labeler); -+ } -+ } -+ -+ return GDK_FILTER_CONTINUE; -+} -+ -+static void -+cc_rr_labeler_init (CcRRLabeler *labeler) -+{ -+ GdkWindow *gdkwindow; -+ -+ labeler->priv = G_TYPE_INSTANCE_GET_PRIVATE (labeler, GNOME_TYPE_RR_LABELER, CcRRLabelerPrivate); -+ -+ labeler->priv->workarea_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), -+ "_NET_WORKAREA", -+ True); -+ -+ labeler->priv->screen = gdk_screen_get_default (); -+ /* code is not really designed to handle multiple screens so *shrug* */ -+ gdkwindow = gdk_screen_get_root_window (labeler->priv->screen); -+ gdk_window_add_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler); -+ gdk_window_set_events (gdkwindow, gdk_window_get_events (gdkwindow) | GDK_PROPERTY_CHANGE_MASK); -+} -+ -+static void -+cc_rr_labeler_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *param_spec) -+{ -+ CcRRLabeler *self = CC_RR_LABELER (gobject); -+ -+ switch (property_id) { -+ case PROP_CONFIG: -+ self->priv->config = GNOME_RR_CONFIG (g_value_dup_object (value)); -+ return; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, param_spec); -+ } -+} -+ -+static GObject * -+cc_rr_labeler_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) -+{ -+ CcRRLabeler *self = (CcRRLabeler*) G_OBJECT_CLASS (cc_rr_labeler_parent_class)->constructor (type, n_construct_properties, construct_properties); -+ -+ setup_from_config (self); -+ -+ return (GObject*) self; -+} -+ -+static void -+cc_rr_labeler_class_init (CcRRLabelerClass *klass) -+{ -+ GObjectClass *object_class; -+ -+ g_type_class_add_private (klass, sizeof (CcRRLabelerPrivate)); -+ -+ object_class = (GObjectClass *) klass; -+ -+ object_class->set_property = cc_rr_labeler_set_property; -+ object_class->finalize = cc_rr_labeler_finalize; -+ object_class->constructor = cc_rr_labeler_constructor; -+ -+ g_object_class_install_property (object_class, PROP_CONFIG, g_param_spec_object ("config", -+ "Configuration", -+ "RandR configuration to label", -+ GNOME_TYPE_RR_CONFIG, -+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | -+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); -+} -+ -+static void -+cc_rr_labeler_finalize (GObject *object) -+{ -+ CcRRLabeler *labeler; -+ GdkWindow *gdkwindow; -+ -+ labeler = CC_RR_LABELER (object); -+ -+ gdkwindow = gdk_screen_get_root_window (labeler->priv->screen); -+ gdk_window_remove_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler); -+ -+ if (labeler->priv->config != NULL) { -+ g_object_unref (labeler->priv->config); -+ } -+ -+ if (labeler->priv->windows != NULL) { -+ cc_rr_labeler_hide (labeler); -+ g_free (labeler->priv->windows); -+ } -+ -+ g_free (labeler->priv->palette); -+ -+ G_OBJECT_CLASS (cc_rr_labeler_parent_class)->finalize (object); -+} -+ -+static int -+count_outputs (GnomeRRConfig *config) -+{ -+ int i; -+ GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); -+ -+ for (i = 0; outputs[i] != NULL; i++) -+ ; -+ -+ return i; -+} -+ -+static void -+make_palette (CcRRLabeler *labeler) -+{ -+ /* The idea is that we go around an hue color wheel. We want to start -+ * at red, go around to green/etc. and stop at blue --- because magenta -+ * is evil. Eeeeek, no magenta, please! -+ * -+ * Purple would be nice, though. Remember that we are watered down -+ * (i.e. low saturation), so that would be like Like berries with cream. -+ * Mmmmm, berries. -+ */ -+ double start_hue; -+ double end_hue; -+ int i; -+ -+ g_assert (labeler->priv->num_outputs > 0); -+ -+ labeler->priv->palette = g_new (GdkRGBA, labeler->priv->num_outputs); -+ -+ start_hue = 0.0; /* red */ -+ end_hue = 2.0/3; /* blue */ -+ -+ for (i = 0; i < labeler->priv->num_outputs; i++) { -+ double h, s, v; -+ double r, g, b; -+ -+ h = start_hue + (end_hue - start_hue) / labeler->priv->num_outputs * i; -+ s = 1.0 / 3; -+ v = 1.0; -+ -+ gtk_hsv_to_rgb (h, s, v, &r, &g, &b); -+ -+ labeler->priv->palette[i].red = r; -+ labeler->priv->palette[i].green = g; -+ labeler->priv->palette[i].blue = b; -+ labeler->priv->palette[i].alpha = 1.0; -+ } -+} -+ -+static void -+rounded_rectangle (cairo_t *cr, -+ gint x, -+ gint y, -+ gint width, -+ gint height, -+ gint x_radius, -+ gint y_radius) -+{ -+ gint x1, x2; -+ gint y1, y2; -+ gint xr1, xr2; -+ gint yr1, yr2; -+ -+ x1 = x; -+ x2 = x1 + width; -+ y1 = y; -+ y2 = y1 + height; -+ -+ x_radius = MIN (x_radius, width / 2.0); -+ y_radius = MIN (y_radius, width / 2.0); -+ -+ xr1 = x_radius; -+ xr2 = x_radius / 2.0; -+ yr1 = y_radius; -+ yr2 = y_radius / 2.0; -+ -+ cairo_move_to (cr, x1 + xr1, y1); -+ cairo_line_to (cr, x2 - xr1, y1); -+ cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1); -+ cairo_line_to (cr, x2, y2 - yr1); -+ cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2); -+ cairo_line_to (cr, x1 + xr1, y2); -+ cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1); -+ cairo_line_to (cr, x1, y1 + yr1); -+ cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1); -+ cairo_close_path (cr); -+} -+ -+#define LABEL_WINDOW_EDGE_THICKNESS 2 -+#define LABEL_WINDOW_PADDING 12 -+/* Look for panel-corner in: -+ * http://git.gnome.org/browse/gnome-shell/tree/data/theme/gnome-shell.css -+ * to match the corner radius */ -+#define LABEL_CORNER_RADIUS 6 + LABEL_WINDOW_EDGE_THICKNESS -+ -+static void -+label_draw_background_and_frame (GtkWidget *widget, cairo_t *cr, gboolean for_shape) -+{ -+ GdkRGBA shape_color = { 0, 0, 0, 1 }; -+ GdkRGBA *rgba; -+ GtkAllocation allocation; -+ -+ rgba = g_object_get_data (G_OBJECT (widget), "rgba"); -+ gtk_widget_get_allocation (widget, &allocation); -+ -+ cairo_save (cr); -+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); -+ -+ /* edge outline */ -+ if (for_shape) -+ gdk_cairo_set_source_rgba (cr, &shape_color); -+ else -+ cairo_set_source_rgba (cr, 0, 0, 0, 0.5); -+ -+ rounded_rectangle (cr, -+ LABEL_WINDOW_EDGE_THICKNESS / 2.0, -+ LABEL_WINDOW_EDGE_THICKNESS / 2.0, -+ allocation.width - LABEL_WINDOW_EDGE_THICKNESS, -+ allocation.height - LABEL_WINDOW_EDGE_THICKNESS, -+ LABEL_CORNER_RADIUS, LABEL_CORNER_RADIUS); -+ cairo_set_line_width (cr, LABEL_WINDOW_EDGE_THICKNESS); -+ cairo_stroke (cr); -+ -+ /* fill */ -+ if (for_shape) { -+ gdk_cairo_set_source_rgba (cr, &shape_color); -+ } else { -+ rgba->alpha = 0.75; -+ gdk_cairo_set_source_rgba (cr, rgba); -+ } -+ -+ rounded_rectangle (cr, -+ LABEL_WINDOW_EDGE_THICKNESS, -+ LABEL_WINDOW_EDGE_THICKNESS, -+ allocation.width - LABEL_WINDOW_EDGE_THICKNESS * 2, -+ allocation.height - LABEL_WINDOW_EDGE_THICKNESS * 2, -+ LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0, -+ LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0); -+ cairo_fill (cr); -+ -+ cairo_restore (cr); -+} -+ -+static void -+maybe_update_shape (GtkWidget *widget) -+{ -+ cairo_t *cr; -+ cairo_surface_t *surface; -+ cairo_region_t *region; -+ -+ /* fallback to XShape only for non-composited clients */ -+ if (gtk_widget_is_composited (widget)) { -+ gtk_widget_shape_combine_region (widget, NULL); -+ return; -+ } -+ -+ surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), -+ CAIRO_CONTENT_COLOR_ALPHA, -+ gtk_widget_get_allocated_width (widget), -+ gtk_widget_get_allocated_height (widget)); -+ -+ cr = cairo_create (surface); -+ label_draw_background_and_frame (widget, cr, TRUE); -+ cairo_destroy (cr); -+ -+ region = gdk_cairo_region_create_from_surface (surface); -+ gtk_widget_shape_combine_region (widget, region); -+ -+ cairo_surface_destroy (surface); -+ cairo_region_destroy (region); -+} -+ -+static gboolean -+label_window_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -+{ -+ if (gtk_widget_is_composited (widget)) { -+ /* clear any content */ -+ cairo_save (cr); -+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); -+ cairo_set_source_rgba (cr, 0, 0, 0, 0); -+ cairo_paint (cr); -+ cairo_restore (cr); -+ } -+ -+ maybe_update_shape (widget); -+ label_draw_background_and_frame (widget, cr, FALSE); -+ -+ return FALSE; -+} -+ -+static void -+position_window (CcRRLabeler *labeler, -+ GtkWidget *window, -+ int x, -+ int y) -+{ -+ GdkRectangle workarea; -+ GdkRectangle monitor; -+ int monitor_num; -+ -+ monitor_num = gdk_screen_get_monitor_at_point (labeler->priv->screen, x, y); -+ gdk_screen_get_monitor_workarea (labeler->priv->screen, monitor_num, &workarea); -+ gdk_screen_get_monitor_geometry (labeler->priv->screen, -+ monitor_num, -+ &monitor); -+ gdk_rectangle_intersect (&monitor, &workarea, &workarea); -+ -+ gtk_window_move (GTK_WINDOW (window), workarea.x, workarea.y); -+} -+ -+static void -+label_window_realize_cb (GtkWidget *widget) -+{ -+ cairo_region_t *region; -+ -+ /* make the whole window ignore events */ -+ region = cairo_region_create (); -+ gtk_widget_input_shape_combine_region (widget, region); -+ cairo_region_destroy (region); -+ -+ maybe_update_shape (widget); -+} -+ -+static void -+label_window_composited_changed_cb (GtkWidget *widget, CcRRLabeler *labeler) -+{ -+ if (gtk_widget_get_realized (widget)) -+ maybe_update_shape (widget); -+} -+ -+static GtkWidget * -+create_label_window (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba) -+{ -+ GtkWidget *window; -+ GtkWidget *widget; -+ char *str; -+ const char *display_name; -+ GdkRGBA black = { 0, 0, 0, 1.0 }; -+ int x, y; -+ GdkScreen *screen; -+ GdkVisual *visual; -+ -+ window = gtk_window_new (GTK_WINDOW_POPUP); -+ gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP); -+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE); -+ gtk_widget_set_app_paintable (window, TRUE); -+ screen = gtk_widget_get_screen (window); -+ visual = gdk_screen_get_rgba_visual (screen); -+ -+ if (visual != NULL) -+ gtk_widget_set_visual (window, visual); -+ -+ gtk_container_set_border_width (GTK_CONTAINER (window), LABEL_WINDOW_PADDING + LABEL_WINDOW_EDGE_THICKNESS); -+ -+ /* This is semi-dangerous. The color is part of the labeler->palette -+ * array. Note that in cc_rr_labeler_finalize(), we are careful to -+ * free the palette only after we free the windows. -+ */ -+ g_object_set_data (G_OBJECT (window), "rgba", rgba); -+ -+ g_signal_connect (window, "draw", -+ G_CALLBACK (label_window_draw_event_cb), labeler); -+ g_signal_connect (window, "realize", -+ G_CALLBACK (label_window_realize_cb), labeler); -+ g_signal_connect (window, "composited-changed", -+ G_CALLBACK (label_window_composited_changed_cb), labeler); -+ -+ if (gnome_rr_config_get_clone (labeler->priv->config)) { -+ /* Keep this string in sync with gnome-control-center/capplets/display/xrandr-capplet.c:get_display_name() */ -+ -+ /* Translators: this is the feature where what you see on your -+ * laptop's screen is the same as your external projector. -+ * Here, "Mirrored" is being used as an adjective. For example, -+ * the Spanish translation could be "Pantallas en Espejo". -+ */ -+ display_name = _("Mirrored Displays"); -+ } else -+ display_name = gnome_rr_output_info_get_display_name (output); -+ -+ str = g_strdup_printf ("%s", display_name); -+ widget = gtk_label_new (NULL); -+ gtk_label_set_markup (GTK_LABEL (widget), str); -+ g_free (str); -+ -+ /* Make the label explicitly black. We don't want it to follow the -+ * theme's colors, since the label is always shown against a light -+ * pastel background. See bgo#556050 -+ */ -+ gtk_widget_override_color (widget, -+ gtk_widget_get_state_flags (widget), -+ &black); -+ -+ gtk_container_add (GTK_CONTAINER (window), widget); -+ -+ /* Should we center this at the top edge of the monitor, instead of using the upper-left corner? */ -+ gnome_rr_output_info_get_geometry (output, &x, &y, NULL, NULL); -+ position_window (labeler, window, x, y); -+ -+ gtk_widget_show_all (window); -+ -+ return window; -+} -+ -+static void -+setup_from_config (CcRRLabeler *labeler) -+{ -+ labeler->priv->num_outputs = count_outputs (labeler->priv->config); -+ -+ make_palette (labeler); -+ -+ cc_rr_labeler_show (labeler); -+} -+ -+/** -+ * cc_rr_labeler_new: -+ * @config: Configuration of the screens to label -+ * -+ * Create a GUI element that will display colored labels on each connected monitor. -+ * This is useful when users are required to identify which monitor is which, e.g. for -+ * for configuring multiple monitors. -+ * The labels will be shown by default, use cc_rr_labeler_hide to hide them. -+ * -+ * Returns: A new #CcRRLabeler -+ */ -+CcRRLabeler * -+cc_rr_labeler_new (GnomeRRConfig *config) -+{ -+ g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), NULL); -+ -+ return g_object_new (GNOME_TYPE_RR_LABELER, "config", config, NULL); -+} -+ -+/** -+ * cc_rr_labeler_show: -+ * @labeler: A #CcRRLabeler -+ * -+ * Show the labels. -+ */ -+void -+cc_rr_labeler_show (CcRRLabeler *labeler) -+{ -+ int i; -+ gboolean created_window_for_clone; -+ GnomeRROutputInfo **outputs; -+ -+ g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); -+ -+ if (labeler->priv->windows != NULL) -+ return; -+ -+ labeler->priv->windows = g_new (GtkWidget *, labeler->priv->num_outputs); -+ -+ created_window_for_clone = FALSE; -+ -+ outputs = gnome_rr_config_get_outputs (labeler->priv->config); -+ -+ for (i = 0; i < labeler->priv->num_outputs; i++) { -+ if (!created_window_for_clone && gnome_rr_output_info_is_active (outputs[i])) { -+ labeler->priv->windows[i] = create_label_window (labeler, outputs[i], labeler->priv->palette + i); -+ -+ if (gnome_rr_config_get_clone (labeler->priv->config)) -+ created_window_for_clone = TRUE; -+ } else -+ labeler->priv->windows[i] = NULL; -+ } -+} -+ -+/** -+ * cc_rr_labeler_hide: -+ * @labeler: A #CcRRLabeler -+ * -+ * Hide ouput labels. -+ */ -+void -+cc_rr_labeler_hide (CcRRLabeler *labeler) -+{ -+ int i; -+ CcRRLabelerPrivate *priv; -+ -+ g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); -+ -+ priv = labeler->priv; -+ -+ if (priv->windows == NULL) -+ return; -+ -+ for (i = 0; i < priv->num_outputs; i++) -+ if (priv->windows[i] != NULL) { -+ gtk_widget_destroy (priv->windows[i]); -+ priv->windows[i] = NULL; -+ } -+ g_free (priv->windows); -+ priv->windows = NULL; -+} -+ -+/** -+ * cc_rr_labeler_get_rgba_for_output: -+ * @labeler: A #CcRRLabeler -+ * @output: Output device (i.e. monitor) to query -+ * @rgba_out: (out): Color of selected monitor. -+ * -+ * Get the color used for the label on a given output (monitor). -+ */ -+void -+cc_rr_labeler_get_rgba_for_output (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba_out) -+{ -+ int i; -+ GnomeRROutputInfo **outputs; -+ -+ g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); -+ g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (output)); -+ g_return_if_fail (rgba_out != NULL); -+ -+ outputs = gnome_rr_config_get_outputs (labeler->priv->config); -+ -+ for (i = 0; i < labeler->priv->num_outputs; i++) -+ if (outputs[i] == output) { -+ *rgba_out = labeler->priv->palette[i]; -+ return; -+ } -+ -+ g_warning ("trying to get the color for unknown GnomeOutputInfo %p; returning magenta!", output); -+ -+ rgba_out->red = 1.0; -+ rgba_out->green = 0; -+ rgba_out->blue = 1.0; -+ rgba_out->alpha = 1.0; -+} -Index: gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h 2014-02-26 19:03:16.051681370 +0100 -@@ -0,0 +1,64 @@ -+/* gnome-rr-labeler.h - Utility to label monitors to identify them -+ * while they are being configured. -+ * -+ * Copyright 2008, Novell, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome 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 -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ * Author: Federico Mena-Quintero -+ */ -+ -+#ifndef CC_RR_LABELER_H -+#define CC_RR_LABELER_H -+ -+#define GNOME_DESKTOP_USE_UNSTABLE_API -+#include -+ -+#define GNOME_TYPE_RR_LABELER (cc_rr_labeler_get_type ()) -+#define CC_RR_LABELER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_LABELER, CcRRLabeler)) -+#define CC_RR_LABELER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_LABELER, CcRRLabelerClass)) -+#define GNOME_IS_RR_LABELER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_LABELER)) -+#define GNOME_IS_RR_LABELER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_LABELER)) -+#define CC_RR_LABELER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_LABELER, CcRRLabelerClass)) -+ -+typedef struct _CcRRLabeler CcRRLabeler; -+typedef struct _CcRRLabelerClass CcRRLabelerClass; -+typedef struct _CcRRLabelerPrivate CcRRLabelerPrivate; -+ -+struct _CcRRLabeler { -+ GObject parent; -+ -+ /*< private >*/ -+ CcRRLabelerPrivate *priv; -+}; -+ -+struct _CcRRLabelerClass { -+ GObjectClass parent_class; -+}; -+ -+GType cc_rr_labeler_get_type (void); -+ -+CcRRLabeler *cc_rr_labeler_new (GnomeRRConfig *config); -+ -+void cc_rr_labeler_show (CcRRLabeler *labeler); -+ -+void cc_rr_labeler_hide (CcRRLabeler *labeler); -+ -+void cc_rr_labeler_get_rgba_for_output (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba_out); -+ -+#endif -Index: gnome-control-center-3.6.3/configure.ac -=================================================================== ---- gnome-control-center-3.6.3.orig/configure.ac 2014-02-26 19:03:16.059681370 +0100 -+++ gnome-control-center-3.6.3/configure.ac 2014-02-26 19:03:19.000000000 +0100 -@@ -135,7 +135,7 @@ - gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION - polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION - gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) --PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) -+PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0 x11) - PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 - polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) - PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES diff -Nru gnome-control-center-3.6.3/debian/patches/git_new_goa_build.patch gnome-control-center-3.6.3/debian/patches/git_new_goa_build.patch --- gnome-control-center-3.6.3/debian/patches/git_new_goa_build.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_new_goa_build.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -https://bugzilla.gnome.org/show_bug.cgi?id=693261 ---- -Index: gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/online-accounts/cc-online-accounts-model.c 2013-06-14 11:32:21.024067503 +0200 -+++ gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c 2013-06-14 11:32:21.016067502 +0200 -@@ -330,8 +330,8 @@ - icon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error); - if (icon == NULL) - { -- goa_warning ("Error creating GIcon for account: %s (%s, %d)", -- error->message, g_quark_to_string (error->domain), error->code); -+ g_warning ("Error creating GIcon for account: %s (%s, %d)", -+ error->message, g_quark_to_string (error->domain), error->code); - g_error_free (error); - } - -@@ -370,7 +370,7 @@ - GtkTreeIter iter; - if (!find_iter_for_object (model, object, &iter)) - { -- goa_warning ("Error removing object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); -+ g_warning ("Error removing object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); - } - else - { -@@ -385,7 +385,7 @@ - GtkTreeIter iter; - if (!find_iter_for_object (model, object, &iter)) - { -- goa_warning ("Error updating object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); -+ g_warning ("Error updating object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); - } - else - { -Index: gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/online-accounts/cc-online-accounts-panel.c 2013-06-14 11:32:21.024067503 +0200 -+++ gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c 2013-06-14 11:32:21.020067502 +0200 -@@ -147,8 +147,8 @@ - GNOMECC_UI_DIR "/online-accounts.ui", - &error) == 0) - { -- goa_warning ("Error loading UI file: %s (%s, %d)", -- error->message, g_quark_to_string (error->domain), error->code); -+ g_warning ("Error loading UI file: %s (%s, %d)", -+ error->message, g_quark_to_string (error->domain), error->code); - g_error_free (error); - goto out; - } -@@ -189,8 +189,8 @@ - panel->client = goa_client_new_sync (NULL /* GCancellable */, &error); - if (panel->client == NULL) - { -- goa_warning ("Error getting a GoaClient: %s (%s, %d)", -- error->message, g_quark_to_string (error->domain), error->code); -+ g_warning ("Error getting a GoaClient: %s (%s, %d)", -+ error->message, g_quark_to_string (error->domain), error->code); - w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); - gtk_widget_set_sensitive (w, FALSE); - g_error_free (error); diff -Nru gnome-control-center-3.6.3/debian/patches/git_no_glxinfo.patch gnome-control-center-3.6.3/debian/patches/git_no_glxinfo.patch --- gnome-control-center-3.6.3/debian/patches/git_no_glxinfo.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_no_glxinfo.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -From c60221e0b4187a6eaa34dd1ec31e92cccab57349 Mon Sep 17 00:00:00 2001 -From: Giovanni Campagna -Date: Sat, 12 Jan 2013 16:43:21 +0000 -Subject: Don't use glxinfo to access the graphic driver name - -glxinfo is part of mesa-demos, and installing it pulls a lot of unnecessary -programs. We can get the same informations by querying the driver directly. - -https://bugzilla.gnome.org/show_bug.cgi?id=691613 ---- ---- a/configure.ac -+++ b/configure.ac -@@ -136,7 +136,7 @@ - polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION - gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) - PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) --PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 -+PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 - polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) - PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES - gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION ---- a/panels/info/cc-info-panel.c -+++ b/panels/info/cc-info-panel.c -@@ -36,6 +36,10 @@ - #include - #include - -+#include -+#include -+#include -+ - #include "hostname-helper.h" - #include "gsd-disk-space-helper.h" - -@@ -301,54 +305,70 @@ - } - - static char * --get_graphics_data_glx_renderer (void) -+get_graphics_data_glx_renderer () - { -- GError *error; -- GRegex *re; -- GMatchInfo *match_info; -- char *output; -- char *result; -- GString *info; -- -- info = g_string_new (NULL); -- -- error = NULL; -- g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error); -- if (error != NULL) -- { -- g_warning ("Unable to get graphics info: %s", error->message); -- g_error_free (error); -- return NULL; -- } -- -- re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error); -- if (re == NULL) -- { -- g_warning ("Error building regex: %s", error->message); -- g_error_free (error); -- goto out; -- } -- -- g_regex_match (re, output, 0, &match_info); -- while (g_match_info_matches (match_info)) -- { -- char *device; -- -- device = g_match_info_fetch (match_info, 1); -- g_string_append_printf (info, "%s ", device); -- g_free (device); -- -- g_match_info_next (match_info, NULL); -- } -- g_match_info_free (match_info); -- g_regex_unref (re); -- -- out: -- g_free (output); -- result = prettify_info (info->str); -- g_string_free (info, TRUE); -+ Display *display; -+ int attributes[] = { -+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, -+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, -+ GLX_RENDER_TYPE, GLX_RGBA_BIT, -+ None -+ }; -+ int nconfigs; -+ int major, minor; -+ Window window; -+ GLXFBConfig *config; -+ GLXWindow glxwin; -+ GLXContext context; -+ XSetWindowAttributes win_attributes; -+ XVisualInfo *visualInfo; -+ char *renderer; -+ -+ gdk_error_trap_push (); -+ -+ display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); -+ -+ glXQueryVersion (display, &major, &minor); -+ config = glXChooseFBConfig (display, DefaultScreen (display), -+ attributes, &nconfigs); -+ if (config == NULL) { -+ g_warning ("Failed to get OpenGL configuration"); -+ -+ gdk_error_trap_pop_ignored (); -+ return NULL; -+ } -+ visualInfo = glXGetVisualFromFBConfig (display, *config); -+ win_attributes.colormap = XCreateColormap (display, DefaultRootWindow(display), -+ visualInfo->visual, AllocNone ); -+ -+ window = XCreateWindow (display, DefaultRootWindow (display), -+ 0, 0, /* x, y */ -+ 1, 1, /* width, height */ -+ 0, /* border_width */ -+ visualInfo->depth, InputOutput, -+ visualInfo->visual, CWColormap, &win_attributes); -+ glxwin = glXCreateWindow (display, *config, window, NULL); -+ -+ context = glXCreateNewContext (display, *config, GLX_RGBA_TYPE, -+ NULL, TRUE); -+ XFree (config); -+ -+ glXMakeContextCurrent (display, glxwin, glxwin, context); -+ renderer = (char *) glGetString (GL_RENDERER); -+ renderer = renderer ? prettify_info (renderer) : NULL; -+ -+ glXMakeContextCurrent (display, None, None, NULL); -+ glXDestroyContext (display, context); -+ glXDestroyWindow (display, glxwin); -+ XDestroyWindow (display, window); -+ XFree (visualInfo); -+ -+ if (gdk_error_trap_pop () != Success) { -+ g_warning ("Failed to get OpenGL driver info"); -+ return NULL; -+ } - -- return result; -+ return renderer; - } - - static char * diff -Nru gnome-control-center-3.6.3/debian/patches/git_power_gsd_proxies.patch gnome-control-center-3.6.3/debian/patches/git_power_gsd_proxies.patch --- gnome-control-center-3.6.3/debian/patches/git_power_gsd_proxies.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_power_gsd_proxies.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -From 5fb7b67ab6d9928ec792b5025f2093529b7f932f Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Sat, 05 Jan 2013 22:45:58 +0000 -Subject: power: Construct the gsd proxies properly - -The code was not using the correct bus name for the screen proxy. -https://bugzilla.gnome.org/show_bug.cgi?id=691177 ---- ---- a/panels/power/cc-power-panel.c -+++ b/panels/power/cc-power-panel.c -@@ -1029,7 +1029,7 @@ - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, -- "org.gnome.SettingsDaemon", -+ "org.gnome.SettingsDaemon.Power", - "/org/gnome/SettingsDaemon/Power", - "org.gnome.SettingsDaemon.Power", - self->priv->cancellable, diff -Nru gnome-control-center-3.6.3/debian/patches/git_region_update_input_switch.patch gnome-control-center-3.6.3/debian/patches/git_region_update_input_switch.patch --- gnome-control-center-3.6.3/debian/patches/git_region_update_input_switch.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_region_update_input_switch.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -From 4e3a2e1bd5214006e4b0e65616747255dc7d8966 Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Wed, 12 Dec 2012 10:17:02 +0000 -Subject: region: Update for the input source switching keybindings move - -These are now provided by gsettings-desktop-schemas. - -https://bugzilla.gnome.org/show_bug.cgi?id=690105 ---- -Index: gnome-control-center-3.6.3/configure.ac -=================================================================== ---- gnome-control-center-3.6.3.orig/configure.ac 2014-02-26 19:04:31.143683870 +0100 -+++ gnome-control-center-3.6.3/configure.ac 2014-02-26 19:04:31.135683870 +0100 -@@ -112,7 +112,7 @@ - NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 - LIBNOTIFY_REQUIRED_VERSION=0.7.3 - GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 --SCHEMAS_REQUIRED_VERSION=3.5.91 -+SCHEMAS_REQUIRED_VERSION=3.7.2.2 - LIBWACOM_REQUIRED_VERSION=0.6 - CLUTTER_REQUIRED_VERSION=1.11.3 - GOA_REQUIRED_VERSION=3.5.90 -Index: gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/region/gnome-region-panel-input.c 2014-02-26 19:04:31.143683870 +0100 -+++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c 2014-02-26 19:04:32.000000000 +0100 -@@ -1219,19 +1219,19 @@ - static void - update_shortcuts (GtkBuilder *builder) - { -- char *previous, *next; -+ char **previous, **next; - GSettings *settings; - -- settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); -+ settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); - -- previous = g_settings_get_string (settings, "switch-input-source-backward"); -- next = g_settings_get_string (settings, "switch-input-source"); -+ previous = g_settings_get_strv (settings, "switch-input-source-backward"); -+ next = g_settings_get_strv (settings, "switch-input-source"); - -- update_shortcut_label (WID ("prev-source-shortcut-label"), previous); -- update_shortcut_label (WID ("next-source-shortcut-label"), next); -+ update_shortcut_label (WID ("prev-source-shortcut-label"), previous[0]); -+ update_shortcut_label (WID ("next-source-shortcut-label"), next[0]); - -- g_free (previous); -- g_free (next); -+ g_strfreev (previous); -+ g_strfreev (next); - } - - static gboolean diff -Nru gnome-control-center-3.6.3/debian/patches/git-rename-bluetooth-panel.patch gnome-control-center-3.6.3/debian/patches/git-rename-bluetooth-panel.patch --- gnome-control-center-3.6.3/debian/patches/git-rename-bluetooth-panel.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-rename-bluetooth-panel.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -Description: Use the 3.8 filename for the Bluetooth panel so that - the Bluetooth Settings link in GNOME Shell 3.8 works -Index: gnome-control-center-3.6.3/configure.ac -=================================================================== ---- gnome-control-center-3.6.3.orig/configure.ac 2013-07-04 00:08:46.849899534 -0400 -+++ gnome-control-center-3.6.3/configure.ac 2013-07-04 00:08:46.841899534 -0400 -@@ -393,7 +393,7 @@ - panels/background/Makefile - panels/background/gnome-background-panel.desktop.in - panels/bluetooth/Makefile --panels/bluetooth/bluetooth-properties.desktop.in -+panels/bluetooth/gnome-bluetooth-panel.desktop.in - panels/datetime/Makefile - panels/datetime/gnome-datetime-panel.desktop.in - panels/datetime/po-timezones/Makefile -Index: gnome-control-center-3.6.3/panels/bluetooth/Makefile.am -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/bluetooth/Makefile.am 2013-07-04 00:08:46.849899534 -0400 -+++ gnome-control-center-3.6.3/panels/bluetooth/Makefile.am 2013-07-04 00:08:46.845899534 -0400 -@@ -19,8 +19,8 @@ - libbluetooth_la_LDFLAGS = $(PANEL_LDFLAGS) - - desktopdir = $(datadir)/applications --desktop_in_in_files = bluetooth-properties.desktop.in.in --desktop_in_files = bluetooth-properties.desktop.in -+desktop_in_in_files = gnome-bluetooth-panel.desktop.in.in -+desktop_in_files = gnome-bluetooth-panel.desktop.in - desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) - @INTLTOOL_DESKTOP_RULE@ - -Index: gnome-control-center-3.6.3/panels/bluetooth/bluetooth-properties.desktop.in.in -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/bluetooth/bluetooth-properties.desktop.in.in 2013-07-04 00:08:46.849899534 -0400 -+++ /dev/null 1970-01-01 00:00:00.000000000 +0000 -@@ -1,15 +0,0 @@ --[Desktop Entry] --_Name=Bluetooth --_Comment=Configure Bluetooth settings --Icon=bluetooth --Exec=gnome-control-center bluetooth --Terminal=false --Type=Application --Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; --OnlyShowIn=GNOME;Unity; --StartupNotify=true --X-GNOME-Bugzilla-Bugzilla=GNOME --X-GNOME-Bugzilla-Product=gnome-bluetooth --X-GNOME-Bugzilla-Component=properties --X-GNOME-Bugzilla-Version=@VERSION@ --X-GNOME-Settings-Panel=bluetooth -Index: gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 2013-07-04 00:08:46.845899534 -0400 -@@ -0,0 +1,15 @@ -+[Desktop Entry] -+_Name=Bluetooth -+_Comment=Configure Bluetooth settings -+Icon=bluetooth -+Exec=gnome-control-center bluetooth -+Terminal=false -+Type=Application -+Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; -+OnlyShowIn=GNOME;Unity; -+StartupNotify=true -+X-GNOME-Bugzilla-Bugzilla=GNOME -+X-GNOME-Bugzilla-Product=gnome-bluetooth -+X-GNOME-Bugzilla-Component=properties -+X-GNOME-Bugzilla-Version=@VERSION@ -+X-GNOME-Settings-Panel=bluetooth -Index: gnome-control-center-3.6.3/po/POTFILES.in -=================================================================== ---- gnome-control-center-3.6.3.orig/po/POTFILES.in 2013-07-04 00:08:46.849899534 -0400 -+++ gnome-control-center-3.6.3/po/POTFILES.in 2013-07-04 00:08:46.845899534 -0400 -@@ -7,7 +7,7 @@ - panels/background/cc-background-item.c - panels/background/cc-background-panel.c - panels/background/gnome-background-panel.desktop.in.in --panels/bluetooth/bluetooth-properties.desktop.in.in -+panels/bluetooth/gnome-bluetooth-panel.desktop.in.in - [type: gettext/glade]panels/bluetooth/bluetooth.ui - panels/bluetooth/cc-bluetooth-panel.c - panels/color/cc-color-panel.c -Index: gnome-control-center-3.6.3/po/POTFILES.skip -=================================================================== ---- gnome-control-center-3.6.3.orig/po/POTFILES.skip 2012-05-24 10:20:11.000000000 -0400 -+++ gnome-control-center-3.6.3/po/POTFILES.skip 2013-07-04 00:10:38.653901911 -0400 -@@ -1,5 +1,5 @@ - panels/background/gnome-background-panel.desktop.in --panels/bluetooth/bluetooth-properties.desktop.in -+panels/bluetooth/gnome-bluetooth-panel.desktop.in - panels/color/gnome-color-panel.desktop.in - panels/datetime/gnome-datetime-panel.desktop.in - panels/display/gnome-display-panel.desktop.in diff -Nru gnome-control-center-3.6.3/debian/patches/git_rename_natural_scrolling.patch gnome-control-center-3.6.3/debian/patches/git_rename_natural_scrolling.patch --- gnome-control-center-3.6.3/debian/patches/git_rename_natural_scrolling.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_rename_natural_scrolling.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -From 92148a4be791614eaf4582ea540cff82e27134de Mon Sep 17 00:00:00 2001 -From: Ondrej Holy -Date: Tue, 11 Jun 2013 12:58:28 +0000 -Subject: mouse: Rename "Content sticks to fingers" - -...to "Natural scrolling". The previous name was a little bit -disgusting, and people didn't understand its purpose. Using the -same name as OSX means that people will either know it, or be less -afraid of testing it. - -https://bugzilla.gnome.org/show_bug.cgi?id=689128 ---- -diff --git a/panels/mouse/gnome-mouse-properties.ui b/panels/mouse/gnome-mouse-properties.ui -index cd77080..3735903 100644 ---- a/panels/mouse/gnome-mouse-properties.ui -+++ b/panels/mouse/gnome-mouse-properties.ui -@@ -655,7 +655,7 @@ - - - -- C_ontent sticks to fingers -+ _Natural scrolling - False - True - True - diff -Nru gnome-control-center-3.6.3/debian/patches/git_restore_mouse_speed.patch gnome-control-center-3.6.3/debian/patches/git_restore_mouse_speed.patch --- gnome-control-center-3.6.3/debian/patches/git_restore_mouse_speed.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_restore_mouse_speed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -From 59467033f1eb293335e4f54a6033e7417af2cd43 Mon Sep 17 00:00:00 2001 -From: Ondrej Holy -Date: Thu, 02 May 2013 12:29:38 +0000 -Subject: mouse: Restore mouse and touchpad pointer speed - -https://bugzilla.gnome.org/show_bug.cgi?id=699015 ---- -diff --git a/panels/mouse/gnome-mouse-properties.c b/panels/mouse/gnome-mouse-properties.c -index 1336916..36c4067 100644 ---- a/panels/mouse/gnome-mouse-properties.c -+++ b/panels/mouse/gnome-mouse-properties.c -@@ -182,6 +182,9 @@ setup_dialog (GtkBuilder *dialog) - - g_signal_connect (WID ("pointer_speed_scale"), "value-changed", - G_CALLBACK (pointer_speed_scale_event), dialog); -+ g_settings_bind (mouse_settings, "motion-acceleration", -+ gtk_range_get_adjustment (GTK_RANGE (WID ("pointer_speed_scale"))), "value", -+ G_SETTINGS_BIND_DEFAULT); - - /* Trackpad page */ - touchpad_present = touchpad_is_present (); -@@ -204,6 +207,9 @@ setup_dialog (GtkBuilder *dialog) - g_settings_bind (touchpad_settings, "natural-scroll", - WID ("natural_scroll_toggle"), "active", - G_SETTINGS_BIND_DEFAULT); -+ g_settings_bind (touchpad_settings, "motion-acceleration", -+ gtk_range_get_adjustment (GTK_RANGE (WID ("touchpad_pointer_speed_scale"))), "value", -+ G_SETTINGS_BIND_DEFAULT); - - g_signal_connect (WID ("touchpad_pointer_speed_scale"), "value-changed", - G_CALLBACK (pointer_speed_scale_event), dialog); - diff -Nru gnome-control-center-3.6.3/debian/patches/git_set_a11y_wm_theme.patch gnome-control-center-3.6.3/debian/patches/git_set_a11y_wm_theme.patch --- gnome-control-center-3.6.3/debian/patches/git_set_a11y_wm_theme.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_set_a11y_wm_theme.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -From d834ebc3211a11514828b847981784a154924cfc Mon Sep 17 00:00:00 2001 -From: Cosimo Cecchi -Date: Tue, 13 Nov 2012 14:35:12 +0000 -Subject: a11y: also set the WM HighContrast theme when the switch is flipped - -Now that we have a HighContrast-specific WM theme. - -https://bugzilla.gnome.org/show_bug.cgi?id=688257 ---- -diff --git a/panels/universal-access/cc-ua-panel.c b/panels/universal-access/cc-ua-panel.c -index 183b58e..7fe97ae 100644 ---- a/panels/universal-access/cc-ua-panel.c -+++ b/panels/universal-access/cc-ua-panel.c -@@ -40,7 +40,7 @@ - #define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" - #define KEY_GTK_THEME "gtk-theme" - #define KEY_ICON_THEME "icon-theme" -- -+#define KEY_WM_THEME "theme" - - CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel) - -@@ -349,19 +349,24 @@ set_contrast_mapping (const GValue *value, - gpointer user_data) - { - gboolean hc; -- GSettings *settings = user_data; -+ CcUaPanel *self = user_data; -+ CcUaPanelPrivate *priv = self->priv; - GVariant *ret = NULL; - - hc = g_value_get_boolean (value); - if (hc) - { - ret = g_variant_new_string (HIGH_CONTRAST_THEME); -- g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); -+ g_settings_set_string (priv->interface_settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); -+ -+ g_settings_set_string (priv->wm_settings, KEY_WM_THEME, HIGH_CONTRAST_THEME); - } - else - { -- g_settings_reset (settings, KEY_GTK_THEME); -- g_settings_reset (settings, KEY_ICON_THEME); -+ g_settings_reset (priv->interface_settings, KEY_GTK_THEME); -+ g_settings_reset (priv->interface_settings, KEY_ICON_THEME); -+ -+ g_settings_reset (priv->wm_settings, KEY_WM_THEME); - } - - return ret; -@@ -377,7 +382,7 @@ cc_ua_panel_init_seeing (CcUaPanel *self) - "active", G_SETTINGS_BIND_DEFAULT, - get_contrast_mapping, - set_contrast_mapping, -- priv->interface_settings, -+ self, - NULL); - g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR, - WID (priv->builder, "seeing_large_text_switch"), diff -Nru gnome-control-center-3.6.3/debian/patches/git_shell_use_view_style_class.patch gnome-control-center-3.6.3/debian/patches/git_shell_use_view_style_class.patch --- gnome-control-center-3.6.3/debian/patches/git_shell_use_view_style_class.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_shell_use_view_style_class.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -From 688695dbec168b55d9510818d8197ccbdcdf45e4 Mon Sep 17 00:00:00 2001 -From: Cosimo Cecchi -Date: Wed, 5 Dec 2012 09:36:12 -0500 -Subject: [PATCH] shell: use the "view" style class for the main viewport - -Currently, gnome-themes-standard sets a white background on all -GtkViewport widgets. -We want to stop rendering one by default, so add a style class to the -main viewport that ensures it gets the same background as the icon -views it packs inside. - -https://bugzilla.gnome.org/show_bug.cgi?id=689700 ---- - shell/shell.ui | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/shell/shell.ui b/shell/shell.ui -index 60b084c..718cc16 100644 ---- a/shell/shell.ui -+++ b/shell/shell.ui -@@ -129,6 +129,9 @@ - True - queue - none -+ - - - True --- -1.8.0.1 diff -Nru gnome-control-center-3.6.3/debian/patches/git_show_per_window_input_settings.patch gnome-control-center-3.6.3/debian/patches/git_show_per_window_input_settings.patch --- gnome-control-center-3.6.3/debian/patches/git_show_per_window_input_settings.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git_show_per_window_input_settings.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,306 +0,0 @@ -From 4f38c427858a6ef834c04f1a1744b3797351410e Mon Sep 17 00:00:00 2001 -From: Rui Matos -Date: Wed, 09 Jan 2013 13:11:31 +0000 -Subject: region: Add UI for the per-window input sources setting - -https://bugzilla.gnome.org/show_bug.cgi?id=684210 ---- ---- a/panels/region/gnome-region-panel.ui -+++ b/panels/region/gnome-region-panel.ui -@@ -862,111 +862,191 @@ - - - -- -+ - True - False -- 0 -- none - -- -+ - True - False -- 12 -+ 0 -+ none - -- -+ - True - False -- 6 -- 6 -- 6 -+ 12 - -- -+ - True - False -- 0 -- Switch to previous source -+ 6 -+ 6 -+ 6 -+ -+ -+ True -+ False -+ 0 -+ Switch to previous source -+ -+ -+ 0 -+ 0 -+ 1 -+ 1 -+ -+ -+ -+ -+ True -+ False -+ end -+ True -+ Ctrl+Alt+Space -+ -+ -+ -+ 1 -+ 0 -+ 1 -+ 1 -+ -+ -+ -+ -+ True -+ False -+ 0 -+ Switch to next source -+ -+ -+ 0 -+ 1 -+ 1 -+ 1 -+ -+ -+ -+ -+ True -+ False -+ end -+ True -+ Ctrl+Alt+Shift+Space -+ -+ -+ -+ 1 -+ 1 -+ 1 -+ 1 -+ -+ -+ -+ -+ True -+ True -+ Shortcut Settings -+ end -+ -+ -+ 1 -+ 2 -+ 1 -+ 1 -+ -+ - -- -- 0 -- 0 -- 1 -- 1 -- -- -- -- -- True -- False -- end -- True -- Ctrl+Alt+Space -- -- -- -- 1 -- 0 -- 1 -- 1 -- -- -- -- -- True -- False -- 0 -- Switch to next source -- -- -- 0 -- 1 -- 1 -- 1 -- - -+ -+ -+ -+ -+ True -+ False -+ Shortcuts -+ True -+ -+ -+ -+ -+ -+ -+ -+ False -+ False -+ 0 -+ -+ -+ -+ -+ True -+ False -+ 0 -+ none -+ -+ -+ True -+ False -+ 12 - -- -+ - True - False -- end -- True -- Ctrl+Alt+Shift+Space -- -- -- -- 1 -- 1 -- 1 -- 1 -- -- -- -- -- True -- True -- Shortcut Settings -- end -+ 6 -+ 6 -+ 6 -+ -+ -+ True -+ True -+ 0 -+ Use the same source for all windows -+ -+ -+ 0 -+ 0 -+ 1 -+ 1 -+ -+ -+ -+ -+ True -+ True -+ 0 -+ Allow different sources for each window -+ per-window-radio-false -+ -+ -+ 0 -+ 1 -+ 1 -+ 1 -+ -+ - -- -- 1 -- 2 -- 1 -- 1 -- - - - -+ -+ -+ True -+ False -+ Options -+ True -+ -+ -+ -+ -+ - -- -- -- -- True -- False -- Shortcuts -- True -- -- -- -- -+ -+ False -+ False -+ 1 -+ - - - ---- a/panels/region/gnome-region-panel-input.c -+++ b/panels/region/gnome-region-panel-input.c -@@ -1338,6 +1338,18 @@ - "changed::" KEY_INPUT_SOURCES, - G_CALLBACK (input_sources_changed), - builder); -+ -+ g_settings_bind (input_sources_settings, "per-window", -+ WID("per-window-radio-true"), "active", -+ G_SETTINGS_BIND_DEFAULT); -+ g_settings_bind (input_sources_settings, "per-window", -+ WID("per-window-radio-false"), "active", -+ G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); -+ /* because we are in delay-apply mode */ -+ g_signal_connect_swapped (WID("per-window-radio-true"), "clicked", -+ G_CALLBACK (g_settings_apply), input_sources_settings); -+ g_signal_connect_swapped (WID("per-window-radio-false"), "clicked", -+ G_CALLBACK (g_settings_apply), input_sources_settings); - } - - static void diff -Nru gnome-control-center-3.6.3/debian/patches/git-sound-fix-port-handling.patch gnome-control-center-3.6.3/debian/patches/git-sound-fix-port-handling.patch --- gnome-control-center-3.6.3/debian/patches/git-sound-fix-port-handling.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/git-sound-fix-port-handling.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -commit 10a0c18b8e3058144586880019b68ab4ea40ce78 -Author: David Henningsson -Date: Fri Dec 7 16:22:09 2012 +0530 - - sound: Fix port handling for the unknown availability case - - The current code assumes that port availability transitions will be - between YES and NO, and doesn't account for the fact that it may also be - UNKNOWN. This causes spurious entries if the port availability - transitions between YES and UNKNOWN. - -diff --git a/panels/sound/gvc-mixer-control.c b/panels/sound/gvc-mixer-control.c -index 34ddc0c..2f6cf34 100644 ---- a/panels/sound/gvc-mixer-control.c -+++ b/panels/sound/gvc-mixer-control.c -@@ -2138,7 +2138,7 @@ update_card (GvcMixerControl *control, - else { - for (i = 0; i < info->n_ports; i++) { - if (g_strcmp0 (card_port->port, info->ports[i]->name) == 0) { -- if (card_port->available != info->ports[i]->available) { -+ if ((card_port->available == PA_PORT_AVAILABLE_NO) != (info->ports[i]->available == PA_PORT_AVAILABLE_NO)) { - card_port->available = info->ports[i]->available; - g_debug ("sync port availability on card %i, card port name '%s', new available value %i", - gvc_mixer_card_get_index (card), diff -Nru gnome-control-center-3.6.3/debian/patches/more-power-suspend-options.patch gnome-control-center-3.6.3/debian/patches/more-power-suspend-options.patch --- gnome-control-center-3.6.3/debian/patches/more-power-suspend-options.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/more-power-suspend-options.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -Description: Add 20 minutes and 2 hours options to give the user - more fine-grained controls. -Author: Jian-Ding Chen (timchen119) -Last-Update: 2013-10-24 -Bug-Ubuntu: https:/launchpad.net/bugs/1244065 - -Index: b/panels/power/power.ui -=================================================================== ---- a/panels/power/power.ui -+++ b/panels/power/power.ui -@@ -40,6 +40,10 @@ - 600 - - -+ 20 minutes -+ 1200 -+ -+ - 30 minutes - 1800 - -@@ -48,6 +52,10 @@ - 3600 - - -+ 2 hours -+ 7200 -+ -+ - Don't suspend - 0 - diff -Nru gnome-control-center-3.6.3/debian/patches/rename_screenshot_media_keys.patch gnome-control-center-3.6.3/debian/patches/rename_screenshot_media_keys.patch --- gnome-control-center-3.6.3/debian/patches/rename_screenshot_media_keys.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/rename_screenshot_media_keys.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Description: Since Ubuntu's gnome-screenshot doesn't automatically save to the - Pictures directory, don't claim that it does in the Keyboard Shortcuts list -Author: William Hua ---- a/panels/keyboard/01-screenshot.xml.in -+++ b/panels/keyboard/01-screenshot.xml.in -@@ -1,17 +1,14 @@ - - - -- - -+ _description="Take a screenshot"/> - -- - -+ _description="Take a screenshot of a window"/> - -- - -+ _description="Take a screenshot of an area"/> - - diff -Nru gnome-control-center-3.6.3/debian/patches/revert_git_drop_library.patch gnome-control-center-3.6.3/debian/patches/revert_git_drop_library.patch --- gnome-control-center-3.6.3/debian/patches/revert_git_drop_library.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/revert_git_drop_library.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -Index: gnome-control-center-3.6.2/configure.ac -=================================================================== ---- gnome-control-center-3.6.2.orig/configure.ac 2012-11-05 11:20:13.107224844 -0500 -+++ gnome-control-center-3.6.2/configure.ac 2012-11-05 11:20:21.251224504 -0500 -@@ -19,6 +19,14 @@ - LT_PREREQ([2.2]) - LT_INIT - -+# .so version for libgnome-control-center -+LIBGNOMECONTROLCENTER_CURRENT=1 -+LIBGNOMECONTROLCENTER_REVISION=0 -+LIBGNOMECONTROLCENTER_AGE=0 -+AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) -+AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) -+AC_SUBST(LIBGNOMECONTROLCENTER_AGE) -+ - # Internationalization support - - IT_PROG_INTLTOOL([0.40.1]) -@@ -295,7 +303,7 @@ - PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" - AC_SUBST(PANEL_CFLAGS) - --PANEL_LIBS="" -+PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" - AC_SUBST(PANEL_LIBS) - - PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" -@@ -398,6 +406,7 @@ - - AC_OUTPUT([ - Makefile -+shell/libgnome-control-center.pc - panels/Makefile - panels/common/Makefile - panels/background/Makefile -Index: gnome-control-center-3.6.2/shell/libgnome-control-center.pc.in -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gnome-control-center-3.6.2/shell/libgnome-control-center.pc.in 2012-11-05 11:20:21.251224504 -0500 -@@ -0,0 +1,12 @@ -+prefix=@prefix@ -+exec_prefix=@exec_prefix@ -+libdir=@libdir@ -+includedir=@includedir@ -+extensiondir=@libdir@/control-center-1/panels -+ -+Name: libgnome-control-center -+Description: A library to create GNOME Control Center extensions -+Version: @VERSION@ -+Requires: glib-2.0 gio-2.0 gtk+-3.0 -+Libs: -L${libdir} -lgnome-control-center -+Cflags: -I${includedir}/gnome-control-center-1 -Index: gnome-control-center-3.6.2/panels/common/Makefile.am -=================================================================== ---- gnome-control-center-3.6.2.orig/panels/common/Makefile.am 2012-11-05 11:19:44.763226029 -0500 -+++ gnome-control-center-3.6.2/panels/common/Makefile.am 2012-11-05 11:20:21.251224504 -0500 -@@ -23,9 +23,10 @@ - cc-language-chooser.h - - liblanguage_la_LIBADD = \ -+ $(PANEL_LIBS) \ - $(LIBLANGUAGE_LIBS) - --liblanguage_la_LDFLAGS = -export_dynamic -avoid-version -module -no-undefined -+liblanguage_la_LDFLAGS = $(PANEL_LDFLAGS) - - list_languages_SOURCES = list-languages.c - list_languages_LDADD = liblanguage.la -Index: gnome-control-center-3.6.2/shell/gnome-control-center.c -=================================================================== ---- gnome-control-center-3.6.2.orig/shell/gnome-control-center.c 2012-11-05 11:20:03.515225245 -0500 -+++ gnome-control-center-3.6.2/shell/gnome-control-center.c 2012-11-05 11:20:21.251224504 -0500 -@@ -214,7 +214,23 @@ - - if (panel_type == G_TYPE_INVALID) - { -- g_warning ("Could not find the loadable module for panel '%s'", id); -+ GKeyFile *key_file; -+ -+ /* It might be an external panel */ -+ key_file = g_key_file_new (); -+ if (g_key_file_load_from_file (key_file, desktop_file, G_KEY_FILE_NONE, NULL)) -+ { -+ gchar *command; -+ -+ command = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); -+ if (command && command[0]) -+ { -+ g_spawn_command_line_async (command, NULL); -+ g_free (command); -+ } -+ } -+ -+ g_key_file_free (key_file); - return FALSE; - } - -Index: gnome-control-center-3.6.2/shell/Makefile.am -=================================================================== ---- gnome-control-center-3.6.2.orig/shell/Makefile.am 2012-11-05 11:19:44.763226029 -0500 -+++ gnome-control-center-3.6.2/shell/Makefile.am 2012-11-05 11:20:21.251224504 -0500 -@@ -26,20 +26,48 @@ - cc-shell-model.h \ - cc-shell-nav-bar.c \ - cc-shell-nav-bar.h \ -- cc-editable-entry.c \ -- cc-editable-entry.h \ -- cc-panel.c \ -- cc-panel.h \ -- cc-shell.c \ -- cc-shell.h \ - $(MARSHAL_FILES) - - gnome_control_center_LDADD = \ -+ libgnome-control-center.la \ - $(SHELL_LIBS) \ - $(CHEESE_LIBS) - - gnome_control_center_LDFLAGS = -export-dynamic - -+lib_LTLIBRARIES = libgnome-control-center.la -+ -+libgnome_control_center_include_HEADERS = \ -+ cc-panel.h \ -+ cc-shell.h \ -+ cc-editable-entry.h \ -+ $(NULL) -+ -+libgnome_control_center_la_SOURCES = \ -+ cc-panel.c \ -+ cc-panel.h \ -+ cc-shell.c \ -+ cc-shell.h \ -+ cc-editable-entry.c \ -+ cc-editable-entry.h \ -+ $(NULL) -+ -+libgnome_control_center_la_LDFLAGS = \ -+ -no-undefined \ -+ -version-info $(LIBGNOMECONTROLCENTER_CURRENT):$(LIBGNOMECONTROLCENTER_REVISION):$(LIBGNOMECONTROLCENTER_AGE) \ -+ $(NULL) -+ -+libgnome_control_center_la_LIBADD = \ -+ $(LIBGNOME_CONTROL_CENTER_LIBS) \ -+ $(NULL) -+ -+libgnome_control_center_la_LIBTOOLFLAGS = --tag=disable-static -+ -+libgnome_control_center_includedir = $(includedir)/gnome-control-center-1/libgnome-control-center -+ -+pkgconfigdir=$(libdir)/pkgconfig -+pkgconfig_DATA=libgnome-control-center.pc -+ - AM_CPPFLAGS = \ - -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ - -DUIDIR="\"$(uidir)\"" \ -@@ -70,6 +98,7 @@ - gnome-control-center.desktop.in.in \ - gnomecc.directory.in \ - gnomecc.menu.in \ -+ libgnome-control-center.pc.in \ - cc-shell-marshal.list - - DISTCLEANFILES = gnome-control-center.desktop gnome-control-center.desktop.in gnomecc.directory gnomecc.menu diff -Nru gnome-control-center-3.6.3/debian/patches/sanitize_ssid_convert_utf8.patch gnome-control-center-3.6.3/debian/patches/sanitize_ssid_convert_utf8.patch --- gnome-control-center-3.6.3/debian/patches/sanitize_ssid_convert_utf8.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/sanitize_ssid_convert_utf8.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -From: Mathieu Trudel-Lapierre -Subject: Properly convert an access point SSID into a format that can be displayed. - -Use nm_utils_ssid_to_utf8() as used elsewhere in the code, rather than using -nm_utils_escape_ssid() (which doesn't in fact convert into an UTF8 string), so -that we have something sane that can be passed to g_markup_escape_text(). - ---- - panels/network/net-device-wifi.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -Index: b/panels/network/net-device-wifi.c -=================================================================== ---- a/panels/network/net-device-wifi.c -+++ b/panels/network/net-device-wifi.c -@@ -150,7 +150,7 @@ add_access_point (NetDeviceWifi *device_ - ssid = nm_access_point_get_ssid (ap); - if (ssid == NULL) - return; -- ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); -+ ssid_text = nm_utils_ssid_to_utf8 (ssid); - title = g_markup_escape_text (ssid_text, -1); - - is_active_ap = active && nm_utils_same_ssid (ssid, nm_access_point_get_ssid (active), TRUE); -@@ -172,6 +172,7 @@ add_access_point (NetDeviceWifi *device_ - COLUMN_AP_OUT_OF_RANGE, FALSE, - COLUMN_AP_IS_SAVED, FALSE, - -1); -+ g_free (ssid_text); - g_free (title); - } - -@@ -531,7 +532,7 @@ add_saved_connection (NetDeviceWifi *dev - return; - - ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (setting)); -- ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); -+ ssid_text = nm_utils_ssid_to_utf8 (ssid); - title = g_markup_escape_text (ssid_text, -1); - g_debug ("got saved %s", title); - -@@ -559,6 +560,7 @@ add_saved_connection (NetDeviceWifi *dev - COLUMN_AP_IS_SAVED, TRUE, - -1); - g_free (title); -+ g_free (ssid_text); - } - - static void -@@ -1074,7 +1076,7 @@ wireless_try_to_connect (NetDeviceWifi * - const gchar *ap_object_path) - { - const GByteArray *ssid; -- const gchar *ssid_tmp; -+ const gchar *ssid_tmp = NULL; - GSList *list, *l; - GSList *filtered; - NMConnection *connection_activate = NULL; -@@ -1112,15 +1114,18 @@ wireless_try_to_connect (NetDeviceWifi * - ssid = nm_setting_wireless_get_ssid (setting_wireless); - if (ssid == NULL) - continue; -- ssid_tmp = nm_utils_escape_ssid (ssid->data, ssid->len); -+ ssid_tmp = nm_utils_ssid_to_utf8 (ssid); - if (g_strcmp0 (ssid_target, ssid_tmp) == 0) { - g_debug ("we found an existing connection %s to activate!", - nm_connection_get_id (connection)); - connection_activate = connection; - break; - } -+ g_free (ssid_tmp); -+ ssid_tmp = NULL; - } - -+ g_free (ssid_tmp); - g_slist_free (list); - g_slist_free (filtered); - diff -Nru gnome-control-center-3.6.3/debian/patches/series gnome-control-center-3.6.3/debian/patches/series --- gnome-control-center-3.6.3/debian/patches/series 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -git_keyboard_grp_xkb_option.patch -0001-online-accounts-use-the-async-function-to-get-all-th.patch -0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch -05_run_update_manager.patch -06_handle_passwd_with_ldap.patch -11_power-configure_lid_action.patch -12_add_never_turn_screen_off.patch -51_unity_options_in_display_panel.patch -52_region_language.patch -53_use_ubuntu_help.patch -54_enable_alt_tap_in_shortcut.patch -55_user_accounts_hide_controls.patch -56_use_ubuntu_info_branding.patch -58_hide_gdm_notifications.patch -58_ubuntu_icon_views_redesign.patch -59_install_gcm_components_on_demand.patch -60_ubuntu_nav_bar.patch -61_workaround_online_account.patch -64_restore_terminal_keyboard_shortcut.patch -90_force_fallback.patch -91_unity_no_printing_panel.patch -92_ubuntu_system_proxy.patch -97_unity_power_ui.patch -98_default_sound_theme.patch -revert_git_drop_library.patch -99_add_lock-on-suspend.patch -dont_download_local_image.patch -classic_use_sound_indicator.patch -accounts_fix_unsetting_icon.patch -git_set_a11y_wm_theme.patch -git-sound-fix-port-handling.patch -unity_background_is_appareance.patch -git-add-21_9_display.patch -git_no_glxinfo.patch -git-fix-background-panel-crash.patch -git_move_rr_labeler.patch -git_new_goa_build.patch -git-rename-bluetooth-panel.patch -zz_add_fallback_panels_dir.patch -rename_screenshot_media_keys.patch -git_show_per_window_input_settings.patch -git_power_gsd_proxies.patch -ubuntu_update_lock_and_power_settings.patch -git_region_update_input_switch.patch -git_keyboard_update_input_switch.patch -git_shell_use_view_style_class.patch -git-background-remove-unused-widget.patch -git-background-lock-screen.patch -git_rename_natural_scrolling.patch -git_hide_unavailable_layout_settings_btn.patch -git_restore_mouse_speed.patch -git_drop_ibus_engine_whitelist.patch -git_add_printer_crash.patch -ubuntu_update_translations_template.patch -unity_no_zoom_controls.patch -more-power-suspend-options.patch -sanitize_ssid_convert_utf8.patch -git_iconview_columns.patch -gcc_not_in_unity.patch diff -Nru gnome-control-center-3.6.3/debian/patches/ubuntu_update_lock_and_power_settings.patch gnome-control-center-3.6.3/debian/patches/ubuntu_update_lock_and_power_settings.patch --- gnome-control-center-3.6.3/debian/patches/ubuntu_update_lock_and_power_settings.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/ubuntu_update_lock_and_power_settings.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -Description: Update for changes in gsettings keys for gnome-settings-daemon 3.8 - - gnome-control-center (1:3.6.3-0ubuntu30~saucy3) saucy; urgency=medium - . - * Apply git patches to support changes in g-s-d 3.8 - * debian/patches: - - git_power_gsd_proxies.patch, - Use correct interface for dbus proxy. - - wacom_update_files_from_gsd.patch, - update wacom plugin files from g-s-d -Author: Tim Lunn -Forwarded: no, Ubuntu Specific - - ---- a/panels/screen/cc-screen-panel.c -+++ b/panels/screen/cc-screen-panel.c -@@ -350,9 +350,7 @@ - 1, &value, - -1); - -- /* set both battery and ac keys */ -- g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); -- g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); -+ g_settings_set (self->priv->session_settings, "idle-delay", "u", value); - - set_idle_delay_from_dpms (self, value); - } -@@ -398,7 +396,7 @@ - i = 0; - - /* try to make the UI match the AC setting */ -- value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); -+ g_settings_get (self->priv->session_settings, "idle-delay", "u", &value); - do - { - gtk_tree_model_get (model, &iter, -@@ -509,7 +507,7 @@ - /* bind the auto dim checkbox */ - widget = WID ("screen_auto_reduce_checkbutton"); - g_settings_bind (self->priv->gsd_settings, -- "idle-dim-battery", -+ "idle-dim", - widget, "active", - G_SETTINGS_BIND_DEFAULT); - diff -Nru gnome-control-center-3.6.3/debian/patches/ubuntu_update_translations_template.patch gnome-control-center-3.6.3/debian/patches/ubuntu_update_translations_template.patch --- gnome-control-center-3.6.3/debian/patches/ubuntu_update_translations_template.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/ubuntu_update_translations_template.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# Description: files to translate from ubuntu patches -Index: gnome-control-center-3.6.3/po/POTFILES.in -=================================================================== ---- gnome-control-center-3.6.3.orig/po/POTFILES.in 2014-02-26 19:01:53.387678617 +0100 -+++ gnome-control-center-3.6.3/po/POTFILES.in 2014-02-26 19:02:22.587679589 +0100 -@@ -98,6 +98,9 @@ - panels/sound/gvc-speaker-test.c - panels/sound/gvc-stream-status-icon.c - panels/sound/sound-theme-file-utils.c -+panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in -+panels/sound-nua/gvc-balance-bar.c -+panels/sound-nua/gvc-mixer-dialog.c - panels/universal-access/cc-ua-panel.c - panels/universal-access/gnome-universal-access-panel.desktop.in.in - [type: gettext/glade]panels/universal-access/uap.ui -@@ -131,7 +134,10 @@ - [type: gettext/glade]panels/wacom/gnome-wacom-properties.ui - panels/wacom/gsd-wacom-device.c - [type: gettext/glade]panels/wacom/wacom-stylus-page.ui -+shell/cc-shell-nav-bar.c - shell/control-center.c - shell/gnomecc.directory.in - shell/gnome-control-center.desktop.in.in - [type: gettext/glade]shell/shell.ui -+panels/display/cc-rr-labeler.c -+ diff -Nru gnome-control-center-3.6.3/debian/patches/unity_background_is_appareance.patch gnome-control-center-3.6.3/debian/patches/unity_background_is_appareance.patch --- gnome-control-center-3.6.3/debian/patches/unity_background_is_appareance.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/unity_background_is_appareance.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Index: gnome-control-center-3.6.3/shell/gnome-control-center.c -=================================================================== ---- gnome-control-center-3.6.3.orig/shell/gnome-control-center.c 2014-02-26 19:04:06.407683047 +0100 -+++ gnome-control-center-3.6.3/shell/gnome-control-center.c 2014-02-26 19:04:09.000000000 +0100 -@@ -1000,6 +1000,10 @@ - - g_clear_pointer (&priv->current_panel_id, g_free); - -+ if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") && -+ !g_strcmp0(start_id, "background")) -+ start_id = "unity-appearance"; -+ - /* clear any custom widgets */ - _shell_remove_all_custom_widgets (priv); - diff -Nru gnome-control-center-3.6.3/debian/patches/unity_no_zoom_controls.patch gnome-control-center-3.6.3/debian/patches/unity_no_zoom_controls.patch --- gnome-control-center-3.6.3/debian/patches/unity_no_zoom_controls.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/unity_no_zoom_controls.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Index: gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c -=================================================================== ---- gnome-control-center-3.6.3.orig/panels/universal-access/cc-ua-panel.c 2013-10-07 15:14:01.510776625 +0200 -+++ gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c 2013-10-07 15:31:38.894811839 +0200 -@@ -429,13 +429,21 @@ - WID (priv->builder, "seeing_toggle_keys_switch"), "active", - G_SETTINGS_BIND_DEFAULT); - -- priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, -+ if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity")) -+ { -+ priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, - "org.gnome.Shell", - G_BUS_NAME_WATCHER_FLAGS_NONE, - (GBusNameAppearedCallback) shell_appeared_cb, - (GBusNameVanishedCallback) shell_vanished_cb, - self, - NULL); -+ } else -+ { -+ gtk_widget_hide (WID (priv->builder, "zoom_label_box")); -+ gtk_widget_hide (WID (priv->builder, "zoom_value_box")); -+ } -+ - g_signal_connect (WID (priv->builder, "seeing_zoom_preferences_button"), - "clicked", - G_CALLBACK (zoom_options_launch_cb), self); diff -Nru gnome-control-center-3.6.3/debian/patches/zz_add_fallback_panels_dir.patch gnome-control-center-3.6.3/debian/patches/zz_add_fallback_panels_dir.patch --- gnome-control-center-3.6.3/debian/patches/zz_add_fallback_panels_dir.patch 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/patches/zz_add_fallback_panels_dir.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -Description: Look in fallback pre-multiarch dir for external panels. -Author: Ryan Lortie -Origin: ubuntu -Forwarded: not-needed - -diff -r -u gnome-control-center-3.6.3/shell/gnome-control-center.c gnome-control-center-3.6.3+awesome/shell/gnome-control-center.c ---- gnome-control-center-3.6.3/shell/gnome-control-center.c 2013-07-08 09:51:42.707462000 -0400 -+++ gnome-control-center-3.6.3/shell/gnome-control-center.c 2013-07-08 09:52:37.723462000 -0400 -@@ -904,6 +904,9 @@ - modules = g_io_modules_load_all_in_directory (PANELS_DIR); - g_list_free (modules); - -+ /* hardcoded fallback from pre-multiarching */ -+ modules = g_io_modules_load_all_in_directory ("/usr/lib/control-center-1/panels"); -+ g_list_free (modules); - } - - diff -Nru gnome-control-center-3.6.3/debian/rules gnome-control-center-3.6.3/debian/rules --- gnome-control-center-3.6.3/debian/rules 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/rules 2015-02-22 15:27:24.000000000 +0000 @@ -27,5 +27,6 @@ rm -rf debian/capplets-data/usr/share/applications/mimeinfo.cache rm -rf debian/capplets-data/usr/share/pkgconfig dh_installmime -p$(cdbs_curpkg) + ./panels/info/logo-generator --logo debian/UbuntuLogoBlank.png --text "ubuntu 14.04 LTS" --output debian/gnome-control-center-data/usr/share/gnome-control-center/ui/UbuntuLogo.png common-binary-post-install-arch:: list-missing diff -Nru gnome-control-center-3.6.3/debian/source/format gnome-control-center-3.6.3/debian/source/format --- gnome-control-center-3.6.3/debian/source/format 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/source/format 2015-02-22 15:27:39.000000000 +0000 @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff -Nru gnome-control-center-3.6.3/debian/source/include-binaries gnome-control-center-3.6.3/debian/source/include-binaries --- gnome-control-center-3.6.3/debian/source/include-binaries 2014-04-10 15:25:34.000000000 +0000 +++ gnome-control-center-3.6.3/debian/source/include-binaries 2015-02-22 15:27:24.000000000 +0000 @@ -1 +1 @@ -debian/UbuntuLogo.png +debian/UbuntuLogoBlank.png Binary files /tmp/qftQarknym/gnome-control-center-3.6.3/debian/UbuntuLogoBlank.png and /tmp/dYyssBrjIX/gnome-control-center-3.6.3/debian/UbuntuLogoBlank.png differ Binary files /tmp/qftQarknym/gnome-control-center-3.6.3/debian/UbuntuLogo.png and /tmp/dYyssBrjIX/gnome-control-center-3.6.3/debian/UbuntuLogo.png differ diff -Nru gnome-control-center-3.6.3/panels/background/background.ui gnome-control-center-3.6.3/panels/background/background.ui --- gnome-control-center-3.6.3/panels/background/background.ui 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/background/background.ui 2015-02-22 15:27:39.000000000 +0000 @@ -4,141 +4,286 @@ True False + 6 + 6 + 6 + 6 10 12 - + True False - 6 + 100 + 100 - + True False - 12 - 0 - none - - False + True - True - True - center + False + 12 + 0 + none + + + True + True + True + center + + + True + False + vertical + + + 310 + 170 + True + False + center + 6 + 6 + 6 + 6 + True + True + + + False + True + 0 + + + + + True + False + Background + + + False + True + 1 + + + + + + + + + True + True + 0 + + + + + True + False + 12 - + True False - True - 18 + center + 12 + 2 - - 417 - 250 + True False - center - 6 - 6 - 6 - 6 - True - True + slideshow-symbolic - True + False True 0 - + + True + False + + + + False + True + 1 + + + + + True False - True - center - 6 - 6 - 6 - True - True + 0 + Changes throughout the day - True + False True 1 + + True + True + 0 + + + False + True + 2 + - True + False True 0 - + True False - 12 - + True False - center - 2 - - - True - False - slideshow-symbolic - - - False - True - 0 - - + 12 + 0 + none - + True - False - 0 - Changes throughout the day + True + True + center + + + True + False + vertical + + + 310 + 170 + True + False + center + 6 + 6 + 6 + 6 + True + True + + + False + True + 0 + + + + + True + False + Lock Screen + + + False + True + 1 + + + + - - False - True - 1 - + + + True + True + 0 + + + + + True + False + 12 - + True False - + center + 12 + 2 + + + True + False + slideshow-symbolic + + + False + True + 0 + + + + + True + False + + + + False + True + 1 + + + + + True + False + 0 + Changes throughout the day + + + False + True + 1 + + - False + True True - 1 + 0 - True + False True - 0 + 2 False True - 2 + 1 @@ -196,8 +341,6 @@ vertical - - diff -Nru gnome-control-center-3.6.3/panels/background/bg-pictures-source.c gnome-control-center-3.6.3/panels/background/bg-pictures-source.c --- gnome-control-center-3.6.3/panels/background/bg-pictures-source.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/background/bg-pictures-source.c 2015-02-22 15:27:39.000000000 +0000 @@ -335,7 +335,7 @@ "shading", G_DESKTOP_BACKGROUND_SHADING_SOLID, "placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM, NULL); - if (source_uri != NULL) + if (source_uri != NULL && !g_file_is_native (file)) g_object_set (G_OBJECT (item), "source-url", source_uri, NULL); g_object_set_data (G_OBJECT (file), "item", item); @@ -413,7 +413,7 @@ GAsyncResult *res, gpointer user_data) { - BgPicturesSource *bg_source = BG_PICTURES_SOURCE (user_data); + BgPicturesSource *bg_source; GList *files, *l; GError *err = NULL; GFile *parent; @@ -423,7 +423,8 @@ if (err) { - g_warning ("Could not get pictures file information: %s", err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Could not get pictures file information: %s", err->message); g_error_free (err); g_list_foreach (files, (GFunc) g_object_unref, NULL); @@ -431,6 +432,8 @@ return; } + bg_source = BG_PICTURES_SOURCE (user_data); + parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); /* iterate over the available files */ @@ -453,7 +456,7 @@ GAsyncResult *res, gpointer user_data) { - BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (user_data)->priv; + BgPicturesSourcePrivate *priv; GFileEnumerator *enumerator; GError *err = NULL; @@ -461,12 +464,15 @@ if (err) { - if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) == FALSE) + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && + !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("Could not fill pictures source: %s", err->message); g_error_free (err); return; } + priv = BG_PICTURES_SOURCE (user_data)->priv; + /* get the files */ g_file_enumerator_next_files_async (enumerator, G_MAXINT, diff -Nru gnome-control-center-3.6.3/panels/background/cc-background-panel.c gnome-control-center-3.6.3/panels/background/cc-background-panel.c --- gnome-control-center-3.6.3/panels/background/cc-background-panel.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/background/cc-background-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -38,6 +38,7 @@ #include "bg-pictures-source.h" #define WP_PATH_ID "org.gnome.desktop.background" +#define WP_LOCK_PATH_ID "org.gnome.desktop.screensaver" #define WP_URI_KEY "picture-uri" #define WP_OPTIONS_KEY "picture-options" #define WP_SHADING_KEY "color-shading-type" @@ -55,10 +56,12 @@ GDBusConnection *connection; GSettings *settings; + GSettings *lock_settings; GnomeDesktopThumbnailFactory *thumb_factory; CcBackgroundItem *current_background; + CcBackgroundItem *current_lock_background; GCancellable *copy_cancellable; GCancellable *capture_cancellable; @@ -70,6 +73,8 @@ }; #define WID(y) (GtkWidget *) gtk_builder_get_object (priv->builder, y) +#define CURRENT_BG (settings == priv->settings ? priv->current_background : priv->current_lock_background) +#define SAVE_PATH (settings == priv->settings ? "last-edited.xml" : "last-edited-lock.xml") static const char * cc_background_panel_get_help_uri (CcPanel *panel) @@ -88,6 +93,7 @@ priv->spinner = NULL; g_clear_object (&priv->settings); + g_clear_object (&priv->lock_settings); if (priv->copy_cancellable) { @@ -124,6 +130,7 @@ CcBackgroundPanelPrivate *priv = CC_BACKGROUND_PANEL (object)->priv; g_clear_object (&priv->current_background); + g_clear_object (&priv->current_lock_background); G_OBJECT_CLASS (cc_background_panel_parent_class)->finalize (object); } @@ -144,59 +151,77 @@ static void update_preview (CcBackgroundPanelPrivate *priv, + GSettings *settings, CcBackgroundItem *item) { gboolean changes_with_time; + CcBackgroundItem *current_background; + + current_background = CURRENT_BG; - if (item && priv->current_background) + if (item && current_background) { - g_object_unref (priv->current_background); - priv->current_background = cc_background_item_copy (item); - cc_background_item_load (priv->current_background, NULL); + g_object_unref (current_background); + current_background = cc_background_item_copy (item); + if (settings == priv->settings) + priv->current_background = current_background; + else + priv->current_lock_background = current_background; + cc_background_item_load (current_background, NULL); } changes_with_time = FALSE; - if (priv->current_background) + if (current_background) { - changes_with_time = cc_background_item_changes_with_time (priv->current_background); + changes_with_time = cc_background_item_changes_with_time (current_background); } - gtk_widget_set_visible (WID ("slide_image"), changes_with_time); - gtk_widget_set_visible (WID ("slide-label"), changes_with_time); + if (settings == priv->settings) + { + gtk_widget_set_visible (WID ("slide_image"), changes_with_time); + gtk_widget_set_visible (WID ("slide-label"), changes_with_time); + + gtk_widget_queue_draw (WID ("background-desktop-drawingarea")); + } + else + { + gtk_widget_set_visible (WID ("slide_image1"), changes_with_time); + gtk_widget_set_visible (WID ("slide-label1"), changes_with_time); - gtk_widget_queue_draw (WID ("background-desktop-drawingarea")); + gtk_widget_queue_draw (WID ("background-lock-drawingarea")); + } } static char * -get_save_path (void) +get_save_path (const char *filename) { return g_build_filename (g_get_user_config_dir (), "gnome-control-center", "backgrounds", - "last-edited.xml", + filename, NULL); } static void -update_display_preview (CcBackgroundPanel *panel) +update_display_preview (CcBackgroundPanel *panel, + GtkWidget *widget, + CcBackgroundItem *current_background) { CcBackgroundPanelPrivate *priv = panel->priv; - GtkWidget *widget; GtkAllocation allocation; - const gint preview_width = 416; - const gint preview_height = 248; + const gint preview_width = 309; + const gint preview_height = 168; GdkPixbuf *pixbuf; GIcon *icon; cairo_t *cr; - widget = WID ("background-desktop-drawingarea"); gtk_widget_get_allocation (widget, &allocation); - if (!priv->current_background) + if (!current_background) return; - icon = cc_background_item_get_frame_thumbnail (priv->current_background, + icon = cc_background_item_get_frame_thumbnail (current_background, priv->thumb_factory, preview_width, preview_height, @@ -211,11 +236,14 @@ g_object_unref (pixbuf); pixbuf = NULL; - if (panel->priv->display_screenshot != NULL) - pixbuf = gdk_pixbuf_scale_simple (panel->priv->display_screenshot, - preview_width, - preview_height, - GDK_INTERP_BILINEAR); + if (current_background == priv->current_background && + panel->priv->display_screenshot != NULL) + { + pixbuf = gdk_pixbuf_scale_simple (panel->priv->display_screenshot, + preview_width, + preview_height, + GDK_INTERP_BILINEAR); + } if (pixbuf) { @@ -260,6 +288,7 @@ error->message); g_error_free (error); /* fallback? */ + priv = panel->priv; goto out; } @@ -307,7 +336,7 @@ cairo_surface_destroy (surface); out: - update_display_preview (panel); + update_display_preview (panel, WID ("background-desktop-drawingarea"), priv->current_background); } static void @@ -356,6 +385,7 @@ cairo_t *cr, CcBackgroundPanel *panel) { + CcBackgroundPanelPrivate *priv = panel->priv; /* we have another shot in flight or an existing cache */ if (panel->priv->display_screenshot == NULL && panel->priv->screenshot_path == NULL) @@ -368,13 +398,24 @@ get_screenshot_async (panel, &rect); } else - update_display_preview (panel); + update_display_preview (panel, widget, priv->current_background); + + return TRUE; +} +static gboolean +on_lock_preview_draw (GtkWidget *widget, + cairo_t *cr, + CcBackgroundPanel *panel) +{ + CcBackgroundPanelPrivate *priv = panel->priv; + update_display_preview (panel, widget, priv->current_lock_background); return TRUE; } static void -reload_current_bg (CcBackgroundPanel *self) +reload_current_bg (CcBackgroundPanel *self, + GSettings *settings) { CcBackgroundPanelPrivate *priv; CcBackgroundItem *saved, *configured; @@ -383,12 +424,12 @@ priv = self->priv; /* Load the saved configuration */ - uri = get_save_path (); + uri = get_save_path (SAVE_PATH); saved = cc_background_xml_get_item (uri); g_free (uri); /* initalise the current background information from settings */ - uri = g_settings_get_string (priv->settings, WP_URI_KEY); + uri = g_settings_get_string (settings, WP_URI_KEY); if (uri && *uri == '\0') { g_free (uri); @@ -404,12 +445,12 @@ configured = cc_background_item_new (uri); g_free (uri); - pcolor = g_settings_get_string (priv->settings, WP_PCOLOR_KEY); - scolor = g_settings_get_string (priv->settings, WP_SCOLOR_KEY); + pcolor = g_settings_get_string (settings, WP_PCOLOR_KEY); + scolor = g_settings_get_string (settings, WP_SCOLOR_KEY); g_object_set (G_OBJECT (configured), "name", _("Current background"), - "placement", g_settings_get_enum (priv->settings, WP_OPTIONS_KEY), - "shading", g_settings_get_enum (priv->settings, WP_SHADING_KEY), + "placement", g_settings_get_enum (settings, WP_OPTIONS_KEY), + "shading", g_settings_get_enum (settings, WP_SHADING_KEY), "primary-color", pcolor, "secondary-color", scolor, NULL); @@ -433,9 +474,17 @@ if (saved != NULL) g_object_unref (saved); - g_clear_object (&priv->current_background); - priv->current_background = configured; - cc_background_item_load (priv->current_background, NULL); + if (settings == priv->settings) + { + g_clear_object (&priv->current_background); + priv->current_background = configured; + } + else + { + g_clear_object (&priv->current_lock_background); + priv->current_lock_background = configured; + } + cc_background_item_load (configured, NULL); } static gboolean @@ -466,6 +515,8 @@ CcBackgroundPanel *panel = (CcBackgroundPanel *) pointer; CcBackgroundPanelPrivate *priv = panel->priv; CcBackgroundItem *item; + CcBackgroundItem *current_background; + GSettings *settings; if (!g_file_copy_finish (G_FILE (source_object), result, &err)) { @@ -477,8 +528,10 @@ g_error_free (err); } item = g_object_get_data (source_object, "item"); + settings = g_object_get_data (source_object, "settings"); + current_background = CURRENT_BG; - g_settings_apply (priv->settings); + g_settings_apply (settings); /* the panel may have been destroyed before the callback is run, so be sure * to check the widgets are not NULL */ @@ -489,19 +542,19 @@ priv->spinner = NULL; } - if (priv->current_background) - cc_background_item_load (priv->current_background, NULL); + if (current_background) + cc_background_item_load (current_background, NULL); if (priv->builder) { char *filename; - update_preview (priv, item); + update_preview (priv, settings, item); /* Save the source XML if there is one */ - filename = get_save_path (); + filename = get_save_path (SAVE_PATH); if (create_save_dir ()) - cc_background_xml_save (priv->current_background, filename); + cc_background_xml_save (current_background, filename); } /* remove the reference taken when the copy was set up */ @@ -510,6 +563,7 @@ static void set_background (CcBackgroundPanel *panel, + GSettings *settings, CcBackgroundItem *item) { CcBackgroundPanelPrivate *priv = panel->priv; @@ -527,8 +581,8 @@ if ((flags & CC_BACKGROUND_ITEM_HAS_URI) && uri == NULL) { - g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE); - g_settings_set_string (priv->settings, WP_URI_KEY, ""); + g_settings_set_enum (settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE); + g_settings_set_string (settings, WP_URI_KEY, ""); } else if (cc_background_item_get_source_url (item) != NULL && cc_background_item_get_needs_download (item)) @@ -585,6 +639,7 @@ * finished */ g_object_ref (panel); g_object_set_data_full (G_OBJECT (source), "item", g_object_ref (item), g_object_unref); + g_object_set_data (G_OBJECT (source), "settings", settings); g_file_copy_async (source, dest, G_FILE_COPY_OVERWRITE, G_PRIORITY_DEFAULT, priv->copy_cancellable, NULL, NULL, @@ -593,7 +648,7 @@ dest_uri = g_file_get_uri (dest); g_object_unref (dest); - g_settings_set_string (priv->settings, WP_URI_KEY, dest_uri); + g_settings_set_string (settings, WP_URI_KEY, dest_uri); g_object_set (G_OBJECT (item), "uri", dest_uri, "needs-download", FALSE, @@ -607,37 +662,37 @@ } else { - g_settings_set_string (priv->settings, WP_URI_KEY, uri); + g_settings_set_string (settings, WP_URI_KEY, uri); } /* Also set the placement if we have a URI and the previous value was none */ if (flags & CC_BACKGROUND_ITEM_HAS_PLACEMENT) { - g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); + g_settings_set_enum (settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); } else if (uri != NULL) { - style = g_settings_get_enum (priv->settings, WP_OPTIONS_KEY); + style = g_settings_get_enum (settings, WP_OPTIONS_KEY); if (style == G_DESKTOP_BACKGROUND_STYLE_NONE) - g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); + g_settings_set_enum (settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); } if (flags & CC_BACKGROUND_ITEM_HAS_SHADING) - g_settings_set_enum (priv->settings, WP_SHADING_KEY, cc_background_item_get_shading (item)); + g_settings_set_enum (settings, WP_SHADING_KEY, cc_background_item_get_shading (item)); - g_settings_set_string (priv->settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item)); - g_settings_set_string (priv->settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item)); + g_settings_set_string (settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item)); + g_settings_set_string (settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item)); /* update the preview information */ if (save_settings != FALSE) { /* Apply all changes */ - g_settings_apply (priv->settings); + g_settings_apply (settings); /* Save the source XML if there is one */ - filename = get_save_path (); + filename = get_save_path (SAVE_PATH); if (create_save_dir ()) - cc_background_xml_save (priv->current_background, filename); + cc_background_xml_save (CURRENT_BG, filename); } } @@ -653,7 +708,7 @@ item = cc_background_chooser_dialog_get_item (CC_BACKGROUND_CHOOSER_DIALOG (dialog)); if (item != NULL) { - set_background (self, item); + set_background (self, g_object_get_data (G_OBJECT (dialog), "settings"), item); g_object_unref (item); } } @@ -662,13 +717,14 @@ } static void -on_background_button_clicked (GtkButton *button, - CcBackgroundPanel *self) +launch_chooser (CcBackgroundPanel *self, + GSettings *settings) { CcBackgroundPanelPrivate *priv = self->priv; GtkWidget *dialog; dialog = cc_background_chooser_dialog_new (); + g_object_set_data (G_OBJECT (dialog), "settings", settings); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (gtk_widget_get_toplevel (WID ("background-panel")))); gtk_widget_show (dialog); @@ -676,12 +732,26 @@ } static void +on_background_button_clicked (GtkButton *button, + CcBackgroundPanel *self) +{ + launch_chooser (self, self->priv->settings); +} + +static void +on_lock_button_clicked (GtkButton *button, + CcBackgroundPanel *self) +{ + launch_chooser (self, self->priv->lock_settings); +} + +static void on_settings_changed (GSettings *settings, gchar *key, CcBackgroundPanel *self) { - reload_current_bg (self); - update_preview (self->priv, NULL); + reload_current_bg (self, settings); + update_preview (self->priv, settings, NULL); } static void @@ -711,6 +781,9 @@ priv->settings = g_settings_new (WP_PATH_ID); g_settings_delay (priv->settings); + priv->lock_settings = g_settings_new (WP_LOCK_PATH_ID); + g_settings_delay (priv->lock_settings); + /* add the top level widget */ widget = WID ("background-panel"); @@ -719,21 +792,30 @@ /* setup preview area */ widget = WID ("background-desktop-drawingarea"); - g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), - self); + g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), self); + widget = WID ("background-lock-drawingarea"); + g_signal_connect (widget, "draw", G_CALLBACK (on_lock_preview_draw), self); priv->copy_cancellable = g_cancellable_new (); priv->capture_cancellable = g_cancellable_new (); priv->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); - reload_current_bg (self); - update_preview (priv, NULL); + /* Load the backgrounds */ + reload_current_bg (self, priv->settings); + update_preview (priv, priv->settings, NULL); + reload_current_bg (self, priv->lock_settings); + update_preview (priv, priv->lock_settings, NULL); + /* Background settings */ g_signal_connect (priv->settings, "changed", G_CALLBACK (on_settings_changed), self); + g_signal_connect (priv->lock_settings, "changed", G_CALLBACK (on_settings_changed), self); + /* Background buttons */ widget = WID ("background-set-button"); g_signal_connect (widget, "clicked", G_CALLBACK (on_background_button_clicked), self); + widget = WID ("background-lock-set-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (on_lock_button_clicked), self); } void diff -Nru gnome-control-center-3.6.3/panels/bluetooth/bluetooth-properties.desktop.in.in gnome-control-center-3.6.3/panels/bluetooth/bluetooth-properties.desktop.in.in --- gnome-control-center-3.6.3/panels/bluetooth/bluetooth-properties.desktop.in.in 2012-05-24 14:20:09.000000000 +0000 +++ gnome-control-center-3.6.3/panels/bluetooth/bluetooth-properties.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -[Desktop Entry] -_Name=Bluetooth -_Comment=Configure Bluetooth settings -Icon=bluetooth -Exec=gnome-control-center bluetooth -Terminal=false -Type=Application -Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; -StartupNotify=true -X-GNOME-Bugzilla-Bugzilla=GNOME -X-GNOME-Bugzilla-Product=gnome-bluetooth -X-GNOME-Bugzilla-Component=properties -X-GNOME-Bugzilla-Version=@VERSION@ -X-GNOME-Settings-Panel=bluetooth diff -Nru gnome-control-center-3.6.3/panels/bluetooth/cc-bluetooth-panel.c gnome-control-center-3.6.3/panels/bluetooth/cc-bluetooth-panel.c --- gnome-control-center-3.6.3/panels/bluetooth/cc-bluetooth-panel.c 2012-11-08 17:55:36.000000000 +0000 +++ gnome-control-center-3.6.3/panels/bluetooth/cc-bluetooth-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -73,7 +73,10 @@ static const char * cc_bluetooth_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/bluetooth"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/bluetooth"; + else + return "help:gnome-help/bluetooth"; } static void diff -Nru gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,15 @@ +[Desktop Entry] +_Name=Bluetooth +_Comment=Configure Bluetooth settings +Icon=bluetooth +Exec=gnome-control-center bluetooth +Terminal=false +Type=Application +Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME; +StartupNotify=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-bluetooth +X-GNOME-Bugzilla-Component=properties +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=bluetooth diff -Nru gnome-control-center-3.6.3/panels/bluetooth/Makefile.am gnome-control-center-3.6.3/panels/bluetooth/Makefile.am --- gnome-control-center-3.6.3/panels/bluetooth/Makefile.am 2012-05-24 14:20:09.000000000 +0000 +++ gnome-control-center-3.6.3/panels/bluetooth/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -19,8 +19,8 @@ libbluetooth_la_LDFLAGS = $(PANEL_LDFLAGS) desktopdir = $(datadir)/applications -desktop_in_in_files = bluetooth-properties.desktop.in.in -desktop_in_files = bluetooth-properties.desktop.in +desktop_in_in_files = gnome-bluetooth-panel.desktop.in.in +desktop_in_files = gnome-bluetooth-panel.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) @INTLTOOL_DESKTOP_RULE@ diff -Nru gnome-control-center-3.6.3/panels/color/cc-color-panel.c gnome-control-center-3.6.3/panels/color/cc-color-panel.c --- gnome-control-center-3.6.3/panels/color/cc-color-panel.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/color/cc-color-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include "cc-color-panel.h" @@ -260,32 +261,148 @@ } static void -gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) +gcm_packagekit_finished_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + GPtrArray *argv = (GPtrArray *)user_data; + GVariant *reply; + GError *error = NULL; + gboolean ret; + + reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + g_variant_unref (reply); + + if (error != NULL) + { + g_warning ("failed to install required component: %s", error->message); + g_ptr_array_unref (argv); + g_error_free (error); + return; + } + + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + g_ptr_array_unref (argv); + if (!ret) + { + g_warning ("failed to run command: %s", error->message); + g_error_free (error); + } +} + +struct gcm_packagekit_closure_data +{ + GPtrArray *argv; + guint xid; +}; + +static void +gcm_packagekit_proxy_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + struct gcm_packagekit_closure_data *data = + (struct gcm_packagekit_closure_data *)user_data; + GDBusProxy *session_installer; + GVariantBuilder *builder; + GError *error = NULL; + + session_installer = g_dbus_proxy_new_for_bus_finish (res, &error); + if (error != NULL) + { + g_warning ("failed to connect to PackageKit interface: %s", + error->message); + g_ptr_array_unref (data->argv); + g_free (data); + g_error_free (error); + return; + } + + builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + g_variant_builder_add (builder, "s", + g_ptr_array_index (data->argv, 0)); + g_dbus_proxy_call (session_installer, + "InstallProvideFiles", + g_variant_new ("(uass)", + data->xid, + builder, + "hide-finished" + ), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &gcm_packagekit_finished_cb, + data->argv); + + g_free (data); + g_variant_builder_unref (builder); +} + +static void +gcm_prefs_install_component (guint xid, GPtrArray *argv) +{ + struct gcm_packagekit_closure_data *data; + data = g_malloc (sizeof (*data)); + data->argv = argv; + data->xid = xid; + g_ptr_array_ref (data->argv); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "org.freedesktop.PackageKit", + "/org/freedesktop/PackageKit", + "org.freedesktop.PackageKit.Modify", + NULL, + &gcm_packagekit_proxy_ready_cb, + data); +} + +static void +gcm_prefs_run_maybe_install (guint xid, gchar *filename, GPtrArray *argv) { gboolean ret; GError *error = NULL; + + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + if (!ret) + { + if ((error->domain == g_spawn_error_quark ()) && + (error->code == G_SPAWN_ERROR_NOENT)) + { + gcm_prefs_install_component (xid, argv); + } + else + { + g_warning ("failed to run command: %s", error->message); + } + g_error_free (error); + } +} + +static void +gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) +{ guint xid; GPtrArray *argv; + gchar *calibrater_filename; CcColorPanelPrivate *priv = prefs->priv; /* get xid */ xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + calibrater_filename = g_build_filename (BINDIR, "gcm-calibrate", NULL); + /* run with modal set */ argv = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-calibrate", NULL)); + g_ptr_array_add (argv, calibrater_filename); g_ptr_array_add (argv, g_strdup ("--device")); g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device))); g_ptr_array_add (argv, g_strdup ("--parent-window")); g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); g_ptr_array_add (argv, NULL); - ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, - NULL, NULL, NULL, &error); - if (!ret) - { - g_warning ("failed to run calibrate: %s", error->message); - g_error_free (error); - } + + gcm_prefs_run_maybe_install (xid, calibrater_filename, argv); + g_ptr_array_unref (argv); } @@ -656,10 +773,9 @@ GtkTreeModel *model; GtkTreeSelection *selection; gchar *options = NULL; + gchar *viewer_filename; GPtrArray *argv = NULL; guint xid; - gboolean ret; - GError *error = NULL; CcColorPanelPrivate *priv = prefs->priv; /* get the selected row */ @@ -677,21 +793,17 @@ /* get xid */ xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + viewer_filename = g_build_filename (BINDIR, "gcm-viewer", NULL); /* open up gcm-viewer as a info pane */ argv = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-viewer", NULL)); + g_ptr_array_add (argv, viewer_filename); g_ptr_array_add (argv, g_strdup ("--profile")); g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile))); g_ptr_array_add (argv, g_strdup ("--parent-window")); g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); g_ptr_array_add (argv, NULL); - ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, - NULL, NULL, NULL, &error); - if (!ret) - { - g_warning ("failed to run calibrate: %s", error->message); - g_error_free (error); - } + + gcm_prefs_run_maybe_install (xid, viewer_filename, argv); g_ptr_array_unref (argv); g_free (options); @@ -995,7 +1107,6 @@ { GtkWidget *widget; CdDeviceRelation relation; - gchar *s; CcColorPanelPrivate *priv = prefs->priv; /* get profile */ @@ -1026,13 +1137,7 @@ /* allow getting profile info */ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "toolbutton_profile_view")); - if ((s = g_find_program_in_path ("gcm-viewer"))) - { - gtk_widget_set_sensitive (widget, TRUE); - g_free (s); - } - else - gtk_widget_set_sensitive (widget, FALSE); + gtk_widget_set_sensitive (widget, TRUE); /* hide device specific stuff */ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, @@ -2285,7 +2390,10 @@ static const char * cc_color_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/color"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/color"; + else + return "help:gnome-help/color"; } static void @@ -2567,6 +2675,12 @@ g_signal_connect (widget, "realize", G_CALLBACK (gcm_prefs_window_realize_cb), prefs); + + widget = WID (priv->builder, "linkbutton_help"); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + g_object_set (G_OBJECT (widget), + "uri", "help:ubuntu-help/color-whyimportant", + NULL); } void diff -Nru gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in 2012-05-24 14:20:09.000000000 +0000 +++ gnome-control-center-3.6.3/panels/color/gnome-color-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=color diff -Nru gnome-control-center-3.6.3/panels/common/cc-common-language.c gnome-control-center-3.6.3/panels/common/cc-common-language.c --- gnome-control-center-3.6.3/panels/common/cc-common-language.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/common/cc-common-language.c 2015-02-22 15:27:38.000000000 +0000 @@ -326,6 +326,66 @@ return language; } +gchar * +cc_common_language_get_property (const gchar *prop_name) +{ + GDBusConnection *bus; + gchar *user_path; + GError *error = NULL; + GVariant *properties; + GVariantIter *iter; + gchar *key; + GVariant *value; + gchar *ret = NULL; + + if (g_strcmp0 (prop_name, "Language") != 0 && g_strcmp0 (prop_name, "FormatsLocale") != 0) { + g_warning ("Invalid argument: '%s'", prop_name); + return ret; + } + + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); + user_path = g_strdup_printf ("/org/freedesktop/Accounts/User%i", getuid ()); + + properties = g_dbus_connection_call_sync (bus, + "org.freedesktop.Accounts", + user_path, + "org.freedesktop.DBus.Properties", + "GetAll", + g_variant_new ("(s)", "org.freedesktop.Accounts.User"), + G_VARIANT_TYPE ("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!properties) { + g_warning ("Error calling GetAll() when retrieving properties for %s: %s", user_path, error->message); + g_error_free (error); + /* g_hash_table_lookup() is not NULL-safe, so don't return NULL */ + if (g_strcmp0 (prop_name, "Language") == 0) + ret = g_strdup ("en"); + else + ret = g_strdup ("en_US.UTF-8"); + goto out; + } + + g_variant_get (properties, "(a{sv})", &iter); + while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { + if (g_strcmp0 (key, prop_name) == 0) { + g_variant_get (value, "s", &ret); + break; + } + } + + g_variant_unref (properties); + g_variant_iter_free (iter); + +out: + g_object_unref (bus); + g_free (user_path); + + return ret; +} + static void languages_foreach_cb (gpointer key, gpointer value, @@ -407,7 +467,7 @@ char *lang; gboolean found; - lang = cc_common_language_get_current_language (); + lang = cc_common_language_get_property ("Language"); g_debug ("Trying to select lang '%s' in treeview", lang); model = gtk_tree_view_get_model (treeview); found = FALSE; @@ -440,6 +500,7 @@ g_warning ("Could not find current language '%s' in the treeview", lang); } +/* static void add_other_users_language (GHashTable *ht) { @@ -519,6 +580,7 @@ g_object_unref (proxy); } +*/ GHashTable * cc_common_language_get_initial_languages (void) @@ -530,6 +592,7 @@ ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); /* Add some common languages first */ +/* g_hash_table_insert (ht, g_strdup ("en_US.utf8"), g_strdup (_("English"))); if (gdm_language_has_translations ("en_GB")) g_hash_table_insert (ht, g_strdup ("en_GB.utf8"), g_strdup (_("British English"))); @@ -550,12 +613,29 @@ if (gdm_language_has_translations ("ar") || gdm_language_has_translations ("ar_EG")) g_hash_table_insert (ht, g_strdup ("ar_EG.utf8"), g_strdup (_("Arabic"))); - +*/ /* Add the languages used by other users on the system */ - add_other_users_language (ht); +// add_other_users_language (ht); + + /* Add installed languages */ + gchar *avail_languages; + GError *error = NULL; + if (g_spawn_command_line_sync ("/usr/share/language-tools/language-options", + &avail_languages, NULL, NULL, &error)) { + name = strtok (avail_languages, "\n"); + while (name != NULL) { + language = gdm_get_language_from_name (name, NULL); + g_hash_table_insert (ht, g_strdup (name), language); + name = strtok (NULL, "\n"); + } + g_free (avail_languages); + } else { + g_warning ("Couldn't get available languages: %s", error->message); + g_error_free (error); + } - /* Add current locale */ - name = cc_common_language_get_current_language (); + /* Add current language */ + name = cc_common_language_get_property ("Language"); if (g_hash_table_lookup (ht, name) == NULL) { language = gdm_get_language_from_name (name, NULL); g_hash_table_insert (ht, name, language); diff -Nru gnome-control-center-3.6.3/panels/common/cc-common-language.h gnome-control-center-3.6.3/panels/common/cc-common-language.h --- gnome-control-center-3.6.3/panels/common/cc-common-language.h 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/common/cc-common-language.h 2015-02-22 15:27:38.000000000 +0000 @@ -45,6 +45,7 @@ GHashTable *user_langs); gboolean cc_common_language_has_font (const gchar *locale); gchar *cc_common_language_get_current_language (void); +gchar *cc_common_language_get_property (const gchar *prop_name); GHashTable *cc_common_language_get_initial_languages (void); GHashTable *cc_common_language_get_initial_regions (const gchar *lang); diff -Nru gnome-control-center-3.6.3/panels/common/cc-language-chooser.c gnome-control-center-3.6.3/panels/common/cc-language-chooser.c --- gnome-control-center-3.6.3/panels/common/cc-language-chooser.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/common/cc-language-chooser.c 2015-02-22 15:27:38.000000000 +0000 @@ -105,8 +105,8 @@ user_langs = cc_common_language_get_initial_languages (); - /* Add the current locale first */ - name = cc_common_language_get_current_language (); + /* Add the current language first */ + name = cc_common_language_get_property ("Language"); display = g_hash_table_lookup (user_langs, name); gtk_list_store_append (store, &iter); @@ -118,8 +118,8 @@ g_hash_table_foreach (user_langs, (GHFunc) languages_foreach_cb, store); /* And now the "Other..." selection */ - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1); +// gtk_list_store_append (store, &iter); +// gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1); g_hash_table_destroy (user_langs); } diff -Nru gnome-control-center-3.6.3/panels/common/gdm-languages.c gnome-control-center-3.6.3/panels/common/gdm-languages.c --- gnome-control-center-3.6.3/panels/common/gdm-languages.c 2012-11-05 08:38:42.000000000 +0000 +++ gnome-control-center-3.6.3/panels/common/gdm-languages.c 2015-02-22 15:27:38.000000000 +0000 @@ -224,6 +224,7 @@ const char *codeset, const char *modifier) { + const char *adj_codeset; char *name; g_assert (language[0] != 0); @@ -231,12 +232,17 @@ g_assert (codeset == NULL || codeset[0] != 0); g_assert (modifier == NULL || modifier[0] != 0); + if (g_strcmp0 (codeset, "utf8") == 0) { + adj_codeset = "UTF-8"; + } else + adj_codeset = codeset; + name = g_strdup_printf ("%s%s%s%s%s%s%s", language, territory != NULL? "_" : "", territory != NULL? territory : "", codeset != NULL? "." : "", - codeset != NULL? codeset : "", + codeset != NULL? adj_codeset : "", modifier != NULL? "@" : "", modifier != NULL? modifier : ""); @@ -854,6 +860,7 @@ const char *ccode_longT; const char *ccode; const char *ccode_id; + const char *lang_common_name; const char *lang_name; if (! (g_str_equal (element_name, "iso_639_entry") || g_str_equal (element_name, "iso_639_3_entry")) @@ -865,6 +872,7 @@ ccode_longB = NULL; ccode_longT = NULL; ccode_id = NULL; + lang_common_name = NULL; lang_name = NULL; while (*attr_names && *attr_values) { @@ -901,6 +909,11 @@ } ccode_id = *attr_values; } + } else if (g_str_equal (*attr_names, "common_name")) { + /* skip if empty */ + if (**attr_values) { + lang_common_name = *attr_values; + } } else if (g_str_equal (*attr_names, "name")) { lang_name = *attr_values; } @@ -909,6 +922,10 @@ ++attr_values; } + if (lang_common_name != NULL) { + lang_name = lang_common_name; + } + if (lang_name == NULL) { return; } @@ -1131,6 +1148,7 @@ char *langinfo_codeset; char *translated_language; char *translated_territory; + char *modifier; gboolean is_utf8 = TRUE; g_return_val_if_fail (name != NULL, NULL); @@ -1153,12 +1171,13 @@ language_code = NULL; territory_code = NULL; codeset_code = NULL; + modifier = NULL; gdm_parse_language_name (name, &language_code, &territory_code, &codeset_code, - NULL); + &modifier); if (language_code == NULL) { goto out; @@ -1184,7 +1203,7 @@ translated_territory); } - language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); +// language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); if (codeset_code == NULL && langinfo_codeset != NULL) { codeset_code = g_strdup (langinfo_codeset); @@ -1196,6 +1215,10 @@ codeset_code); } + if (modifier != NULL) { + g_string_append_printf (full_language, " - %s", modifier); + } + out: g_free (language_code); g_free (territory_code); @@ -1203,6 +1226,7 @@ g_free (langinfo_codeset); g_free (translated_language); g_free (translated_territory); + g_free (modifier); if (full_language->len == 0) { g_string_free (full_language, TRUE); diff -Nru gnome-control-center-3.6.3/panels/common/Makefile.am gnome-control-center-3.6.3/panels/common/Makefile.am --- gnome-control-center-3.6.3/panels/common/Makefile.am 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/common/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -23,9 +23,10 @@ cc-language-chooser.h liblanguage_la_LIBADD = \ + $(PANEL_LIBS) \ $(LIBLANGUAGE_LIBS) -liblanguage_la_LDFLAGS = -export_dynamic -avoid-version -module -no-undefined +liblanguage_la_LDFLAGS = $(PANEL_LDFLAGS) list_languages_SOURCES = list-languages.c list_languages_LDADD = liblanguage.la diff -Nru gnome-control-center-3.6.3/panels/datetime/cc-datetime-panel.c gnome-control-center-3.6.3/panels/datetime/cc-datetime-panel.c --- gnome-control-center-3.6.3/panels/datetime/cc-datetime-panel.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/datetime/cc-datetime-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -178,7 +178,10 @@ static const char * cc_date_time_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/clock"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/clock"; + else + return "help:gnome-help/clock"; } static void diff -Nru gnome-control-center-3.6.3/panels/display/cc-display-panel.c gnome-control-center-3.6.3/panels/display/cc-display-panel.c --- gnome-control-center-3.6.3/panels/display/cc-display-panel.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/cc-display-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -31,12 +31,13 @@ #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include -#include #include #include #include #include +#include "cc-rr-labeler.h" + CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) #define DISPLAY_PANEL_PRIVATE(o) \ @@ -54,6 +55,13 @@ #define MINIMUM_WIDTH 675 #define MINIMUM_HEIGHT 530 +#define UNITY_GSETTINGS_SCHEMA "org.compiz.unityshell" +#define UNITY_GSETTINGS_PATH "/org/compiz/profiles/unity/plugins/unityshell/" +#define UNITY_LAUNCHER_ALL_MONITORS_KEY "num-launchers" +#define UNITY_STICKY_EDGE_KEY "launcher-capture-mouse" +#define UNITY2D_GSETTINGS_MAIN "com.canonical.Unity2d" +#define UNITY2D_GSETTINGS_LAUNCHER "com.canonical.Unity2d.Launcher" + enum { TEXT_COL, WIDTH_COL, @@ -68,10 +76,13 @@ { GnomeRRScreen *screen; GnomeRRConfig *current_configuration; - GnomeRRLabeler *labeler; + CcRRLabeler *labeler; GnomeRROutputInfo *current_output; GSettings *clock_settings; + GSettings *unity_settings; + GSettings *unity2d_settings_main; + GSettings *unity2d_settings_launcher; GtkBuilder *builder; guint focus_id; @@ -119,6 +130,8 @@ guint n_properties, GObjectConstructParam *properties); static void on_screen_changed (GnomeRRScreen *scr, gpointer data); +static void refresh_unity_launcher_placement (CcDisplayPanel *self); +static gboolean unity_launcher_on_all_monitors (GSettings *settings); static void cc_display_panel_get_property (GObject *object, @@ -168,6 +181,13 @@ if (self->priv->clock_settings != NULL) g_object_unref (self->priv->clock_settings); + if (self->priv->unity2d_settings_main != NULL) + g_object_unref (self->priv->unity2d_settings_main); + if (self->priv->unity2d_settings_launcher != NULL) + g_object_unref (self->priv->unity2d_settings_launcher); + if (self->priv->unity_settings != NULL) + g_object_unref (self->priv->unity_settings); + shell = cc_panel_get_shell (CC_PANEL (self)); if (shell != NULL) { @@ -177,7 +197,7 @@ self->priv->focus_id); } - gnome_rr_labeler_hide (self->priv->labeler); + cc_rr_labeler_hide (self->priv->labeler); g_object_unref (self->priv->labeler); G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); @@ -186,7 +206,10 @@ static const char * cc_display_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/prefs-display"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; } static void @@ -231,6 +254,12 @@ } static gboolean +is_unity_session (void) +{ + return (g_strcmp0 (g_getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0); +} + +static gboolean should_show_resolution (gint output_width, gint output_height, gint width, @@ -261,15 +290,18 @@ self->priv->current_output = NULL; if (self->priv->labeler) { - gnome_rr_labeler_hide (self->priv->labeler); + cc_rr_labeler_hide (self->priv->labeler); g_object_unref (self->priv->labeler); } - self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); + self->priv->labeler = cc_rr_labeler_new (self->priv->current_configuration); if (gtk_widget_has_focus (self->priv->panel)) - gnome_rr_labeler_show (self->priv->labeler); + cc_rr_labeler_show (self->priv->labeler); select_current_output_from_dialog_position (self); + + if (is_unity_session ()) + refresh_unity_launcher_placement (self); } static void @@ -607,6 +639,10 @@ gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); + /* set inactive the launcher placement choice */ + gtk_widget_set_sensitive (WID ("launcher_placement_combo"), !mirror_is_active); + gtk_widget_set_sensitive (WID ("stickyedge_switch"), !mirror_is_active); + g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); } @@ -638,7 +674,7 @@ tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); str = g_strdup_printf ("%s", tmp); - gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); + cc_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); use_color = TRUE; g_free (tmp); } @@ -728,6 +764,9 @@ case 17: aspect = "16:9"; break; + case 23: + aspect = "21:9"; + break; case 12: aspect = "5:4"; break; @@ -845,6 +884,7 @@ rebuild_on_off_radios (self); rebuild_resolution_combo (self); rebuild_rotation_combo (self); + refresh_unity_launcher_placement (self); self->priv->ignore_gui_changes = FALSE; } @@ -1729,6 +1769,10 @@ outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); for (i = 0; outputs[i] != NULL; ++i) gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); + + gtk_widget_queue_draw (WID ("self->priv->area")); + /* refresh the combobox */ + refresh_unity_launcher_placement (self); } static void @@ -2030,7 +2074,7 @@ cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); cairo_clip_preserve (cr); - gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); + cc_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); r = output_color.red; g = output_color.green; b = output_color.blue; @@ -2080,7 +2124,30 @@ g_object_unref (layout); cairo_restore (cr); - if (gnome_rr_output_info_get_primary (output)) + /* Only display a launcher on all or primary monitor */ + if (is_unity_session ()) + { + if (gnome_rr_output_info_is_active (output) && (unity_launcher_on_all_monitors (self->priv->unity_settings) || gnome_rr_output_info_get_primary (output))) + { + cairo_rectangle (cr, x, y, 10, h * scale + 0.5); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + cairo_rectangle (cr, x + 1, y + 6, 8, 8); + cairo_rectangle (cr, x + 1, y + 16, 8, 8); + cairo_rectangle (cr, x + 1, y + 26, 8, 8); + cairo_rectangle (cr, x + 1, y + 36, 8, 8); + cairo_rectangle (cr, x + 1, y + h * scale + 0.5 - 10, 8, 8); + cairo_fill (cr); + } + } + + if (gnome_rr_output_info_get_primary (output) && !is_unity_session ()) { const char *clock_format; char *text; @@ -2515,9 +2582,9 @@ if (self->priv->labeler == NULL) return; if (gtk_window_has_toplevel_focus (window)) - gnome_rr_labeler_show (self->priv->labeler); + cc_rr_labeler_show (self->priv->labeler); else - gnome_rr_labeler_hide (self->priv->labeler); + cc_rr_labeler_hide (self->priv->labeler); } static void @@ -2563,6 +2630,233 @@ } static void +stickyedge_widget_refresh (GtkSwitch *switcher, GSettings *settings) +{ + gboolean stickyedge_enabled = g_settings_get_boolean (settings, UNITY_STICKY_EDGE_KEY); + + gtk_switch_set_active (switcher, stickyedge_enabled); +} + +static void +ext_stickyedge_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + stickyedge_widget_refresh (GTK_SWITCH (user_data), settings); +} + +static void +on_stickyedge_changed (GtkSwitch *switcher, GParamSpec *pspec, gpointer user_data) +{ + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gboolean enabled = gtk_switch_get_active (GTK_SWITCH (switcher)); + + /* 3d */ + g_settings_set_boolean (self->priv->unity_settings, UNITY_STICKY_EDGE_KEY, enabled); + /* 2d */ + if (self->priv->unity2d_settings_main) + g_settings_set_boolean (self->priv->unity2d_settings_main, "sticky-edges", enabled); +} + +static gboolean +unity_launcher_on_all_monitors (GSettings *settings) +{ + gint value = g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY); + return (value == 0); +} + +static GdkPixbuf* +get_monitor_pixbuf (CcDisplayPanel *self, GnomeRROutputInfo *output) +{ + GdkRGBA color; + cairo_surface_t *cairo_surface; + cairo_t *cr; + int monitor_width = 30; + int monitor_height = 15; + + cc_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); + + cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); + cr = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, color.red, color.green, color.blue); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0, 0, 0, 1.0); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_stroke (cr); + + return gdk_pixbuf_get_from_surface (cairo_get_target (cr), 0, 0, monitor_width, monitor_height); +} + +static void +refresh_unity_launcher_placement (CcDisplayPanel *self) +{ + GtkWidget *launcher_placement_combo = WID ("launcher_placement_combo"); + GtkListStore *liststore; + GtkTreeIter iter; + GList *connected_outputs = NULL; + GList *list; + gboolean launcher_on_all_monitors = unity_launcher_on_all_monitors (self->priv->unity_settings); + gint index_of_primary_screen = 0; + gint i; + + liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "available_launcher_placement_store"); + gtk_list_store_clear (liststore); + + connected_outputs = list_connected_outputs (self, NULL, NULL); + for (list = connected_outputs, i = 0; list != NULL; list = list->next) + { + char *monitor_name; + GdkPixbuf *monitor_pixbuf; + GnomeRROutputInfo *output = list->data; + + if (!gnome_rr_output_info_is_active (output)) + continue; + + gtk_list_store_append (liststore, &iter); + monitor_name = g_strdup (gnome_rr_output_info_get_display_name (output)); + monitor_pixbuf = get_monitor_pixbuf (self, output); + + gtk_list_store_set (liststore, &iter, 0, monitor_pixbuf, 1, monitor_name, -1); + + /* select it if primary and only one launcher */ + if (gnome_rr_output_info_get_primary (output) && (!launcher_on_all_monitors)) + index_of_primary_screen = i; + i++; + + g_object_unref (monitor_pixbuf); + g_free (monitor_name); + } + + // FIXME: check autosort? + gtk_list_store_append (liststore, &iter); + gtk_list_store_set (liststore, &iter, 0, NULL, 1, _("All displays"), -1); + + if (launcher_on_all_monitors) + index_of_primary_screen = i; + + gtk_combo_box_set_active (GTK_COMBO_BOX (launcher_placement_combo), index_of_primary_screen); +} + +static gboolean +switcher_set_to_launcher_on_all_monitors (CcDisplayPanel *self) +{ + GtkComboBox *combo = GTK_COMBO_BOX (WID ("launcher_placement_combo")); + gint active = gtk_combo_box_get_active (combo); + gint number_items = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), + NULL); + return (active == number_items - 1); +} + +static void +ext_launcher_placement_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + // add some crazyness as 2d/3d are not using the same keys + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gint launcher_unity_value = 0; + + // two options support: all monitors (0)i or just primary desktop (hence set to 1, not any other number) + if (! switcher_set_to_launcher_on_all_monitors (self)) + launcher_unity_value = 1; + + if (g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY) != launcher_unity_value) + refresh_unity_launcher_placement (self); +} + +static void +on_launcher_placement_combo_changed (GtkComboBox *combo, CcDisplayPanel *self) +{ + gint active = gtk_combo_box_get_active (combo); + gint i; + gint index_on_combo = 0; + + if (active < 0) + return; + gint value = 0; + gboolean on_all_monitors = switcher_set_to_launcher_on_all_monitors (self); + + if (!on_all_monitors) { + value = 1; + // set the primary output if needed + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + GnomeRROutputInfo *output = outputs[i]; + if (!gnome_rr_output_info_is_active (output)) + continue; + + if ((active == index_on_combo) && !gnome_rr_output_info_get_primary (output)) + { + set_primary_output (self, output); + break; + } + index_on_combo++; + } + } + + /* 3d */ + if (self->priv->unity_settings) + g_settings_set_int (self->priv->unity_settings, UNITY_LAUNCHER_ALL_MONITORS_KEY, value); + /* 2d */ + if (self->priv->unity2d_settings_launcher) + g_settings_set_boolean (self->priv->unity2d_settings_launcher, "only-one-launcher", !on_all_monitors); +} + +static void +setup_unity_settings (CcDisplayPanel *self) +{ + const gchar * const *schemas; + + /* Only use the unity-2d schema if it's installed */ + schemas = g_settings_list_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY2D_GSETTINGS_LAUNCHER) == 0) + { + self->priv->unity2d_settings_main = g_settings_new (UNITY2D_GSETTINGS_MAIN); + self->priv->unity2d_settings_launcher = g_settings_new (UNITY2D_GSETTINGS_LAUNCHER); + break; + } + schemas++; + } + schemas = g_settings_list_relocatable_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY_GSETTINGS_SCHEMA) == 0) + { + self->priv->unity_settings = g_settings_new_with_path (UNITY_GSETTINGS_SCHEMA, UNITY_GSETTINGS_PATH); + break; + } + schemas++; + } + + if (!self->priv->unity_settings) + return; + + GtkWidget *sticky_edge_switch = WID ("stickyedge_switch"); + g_signal_connect (sticky_edge_switch, "notify::active", + G_CALLBACK (on_stickyedge_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_STICKY_EDGE_KEY, + G_CALLBACK (ext_stickyedge_changed_callback), sticky_edge_switch); + stickyedge_widget_refresh (GTK_SWITCH (sticky_edge_switch), self->priv->unity_settings); + + g_signal_connect (G_OBJECT (WID ("launcher_placement_combo")), "changed", + G_CALLBACK (on_launcher_placement_combo_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_LAUNCHER_ALL_MONITORS_KEY, + G_CALLBACK (ext_launcher_placement_changed_callback), self); +} + +static void cc_display_panel_init (CcDisplayPanel *self) { } @@ -2579,7 +2873,7 @@ CcDisplayPanel *self; CcShell *shell; GtkWidget *toplevel; - gchar *objects[] = {"display-panel", NULL}; + gchar *objects[] = {"display-panel", "available_launcher_placement_store", NULL}; obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); self = CC_DISPLAY_PANEL (obj); @@ -2668,6 +2962,18 @@ g_signal_connect_swapped (WID ("apply_button"), "clicked", G_CALLBACK (apply), self); + /* Unity settings */ + if (is_unity_session ()) + setup_unity_settings (self); + else + { + gtk_widget_hide (WID ("unity_launcher_placement_sep")); + gtk_widget_hide (WID ("launcher_placement_label")); + gtk_widget_hide (WID ("sticky_edge_label")); + gtk_widget_hide (WID ("launcher_placement_combo")); + gtk_widget_hide (WID ("stickyedge_switch")); + } + gtk_widget_show (self->priv->panel); gtk_container_add (GTK_CONTAINER (self), self->priv->panel); @@ -2682,4 +2988,3 @@ CC_TYPE_DISPLAY_PANEL, "display", 0); } - diff -Nru gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c --- gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/cc-rr-labeler.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,601 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * cc-rr-labeler.c - Utility to label monitors to identify them + * while they are being configured. + * + * Copyright 2008, Novell, Inc. + * + * This file is part of the Gnome Library. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Federico Mena-Quintero + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cc-rr-labeler.h" + +struct _CcRRLabelerPrivate { + GnomeRRConfig *config; + + int num_outputs; + + GdkRGBA *palette; + GtkWidget **windows; + + GdkScreen *screen; + Atom workarea_atom; +}; + +enum { + PROP_0, + PROP_CONFIG, + PROP_LAST +}; + +G_DEFINE_TYPE (CcRRLabeler, cc_rr_labeler, G_TYPE_OBJECT); + +static void cc_rr_labeler_finalize (GObject *object); +static void setup_from_config (CcRRLabeler *labeler); + +static GdkFilterReturn +screen_xevent_filter (GdkXEvent *xevent, + GdkEvent *event, + CcRRLabeler *labeler) +{ + XEvent *xev; + + xev = (XEvent *) xevent; + + if (xev->type == PropertyNotify && + xev->xproperty.atom == labeler->priv->workarea_atom) { + /* update label positions */ + if (labeler->priv->windows != NULL) { + cc_rr_labeler_hide (labeler); + cc_rr_labeler_show (labeler); + } + } + + return GDK_FILTER_CONTINUE; +} + +static void +cc_rr_labeler_init (CcRRLabeler *labeler) +{ + GdkWindow *gdkwindow; + + labeler->priv = G_TYPE_INSTANCE_GET_PRIVATE (labeler, GNOME_TYPE_RR_LABELER, CcRRLabelerPrivate); + + labeler->priv->workarea_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), + "_NET_WORKAREA", + True); + + labeler->priv->screen = gdk_screen_get_default (); + /* code is not really designed to handle multiple screens so *shrug* */ + gdkwindow = gdk_screen_get_root_window (labeler->priv->screen); + gdk_window_add_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler); + gdk_window_set_events (gdkwindow, gdk_window_get_events (gdkwindow) | GDK_PROPERTY_CHANGE_MASK); +} + +static void +cc_rr_labeler_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *param_spec) +{ + CcRRLabeler *self = CC_RR_LABELER (gobject); + + switch (property_id) { + case PROP_CONFIG: + self->priv->config = GNOME_RR_CONFIG (g_value_dup_object (value)); + return; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, param_spec); + } +} + +static GObject * +cc_rr_labeler_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) +{ + CcRRLabeler *self = (CcRRLabeler*) G_OBJECT_CLASS (cc_rr_labeler_parent_class)->constructor (type, n_construct_properties, construct_properties); + + setup_from_config (self); + + return (GObject*) self; +} + +static void +cc_rr_labeler_class_init (CcRRLabelerClass *klass) +{ + GObjectClass *object_class; + + g_type_class_add_private (klass, sizeof (CcRRLabelerPrivate)); + + object_class = (GObjectClass *) klass; + + object_class->set_property = cc_rr_labeler_set_property; + object_class->finalize = cc_rr_labeler_finalize; + object_class->constructor = cc_rr_labeler_constructor; + + g_object_class_install_property (object_class, PROP_CONFIG, g_param_spec_object ("config", + "Configuration", + "RandR configuration to label", + GNOME_TYPE_RR_CONFIG, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); +} + +static void +cc_rr_labeler_finalize (GObject *object) +{ + CcRRLabeler *labeler; + GdkWindow *gdkwindow; + + labeler = CC_RR_LABELER (object); + + gdkwindow = gdk_screen_get_root_window (labeler->priv->screen); + gdk_window_remove_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler); + + if (labeler->priv->config != NULL) { + g_object_unref (labeler->priv->config); + } + + if (labeler->priv->windows != NULL) { + cc_rr_labeler_hide (labeler); + g_free (labeler->priv->windows); + } + + g_free (labeler->priv->palette); + + G_OBJECT_CLASS (cc_rr_labeler_parent_class)->finalize (object); +} + +static int +count_outputs (GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) + ; + + return i; +} + +static void +make_palette (CcRRLabeler *labeler) +{ + /* The idea is that we go around an hue color wheel. We want to start + * at red, go around to green/etc. and stop at blue --- because magenta + * is evil. Eeeeek, no magenta, please! + * + * Purple would be nice, though. Remember that we are watered down + * (i.e. low saturation), so that would be like Like berries with cream. + * Mmmmm, berries. + */ + double start_hue; + double end_hue; + int i; + + g_assert (labeler->priv->num_outputs > 0); + + labeler->priv->palette = g_new (GdkRGBA, labeler->priv->num_outputs); + + start_hue = 0.0; /* red */ + end_hue = 2.0/3; /* blue */ + + for (i = 0; i < labeler->priv->num_outputs; i++) { + double h, s, v; + double r, g, b; + + h = start_hue + (end_hue - start_hue) / labeler->priv->num_outputs * i; + s = 1.0 / 3; + v = 1.0; + + gtk_hsv_to_rgb (h, s, v, &r, &g, &b); + + labeler->priv->palette[i].red = r; + labeler->priv->palette[i].green = g; + labeler->priv->palette[i].blue = b; + labeler->priv->palette[i].alpha = 1.0; + } +} + +static void +rounded_rectangle (cairo_t *cr, + gint x, + gint y, + gint width, + gint height, + gint x_radius, + gint y_radius) +{ + gint x1, x2; + gint y1, y2; + gint xr1, xr2; + gint yr1, yr2; + + x1 = x; + x2 = x1 + width; + y1 = y; + y2 = y1 + height; + + x_radius = MIN (x_radius, width / 2.0); + y_radius = MIN (y_radius, width / 2.0); + + xr1 = x_radius; + xr2 = x_radius / 2.0; + yr1 = y_radius; + yr2 = y_radius / 2.0; + + cairo_move_to (cr, x1 + xr1, y1); + cairo_line_to (cr, x2 - xr1, y1); + cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1); + cairo_line_to (cr, x2, y2 - yr1); + cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2); + cairo_line_to (cr, x1 + xr1, y2); + cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1); + cairo_line_to (cr, x1, y1 + yr1); + cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1); + cairo_close_path (cr); +} + +#define LABEL_WINDOW_EDGE_THICKNESS 2 +#define LABEL_WINDOW_PADDING 12 +/* Look for panel-corner in: + * http://git.gnome.org/browse/gnome-shell/tree/data/theme/gnome-shell.css + * to match the corner radius */ +#define LABEL_CORNER_RADIUS 6 + LABEL_WINDOW_EDGE_THICKNESS + +static void +label_draw_background_and_frame (GtkWidget *widget, cairo_t *cr, gboolean for_shape) +{ + GdkRGBA shape_color = { 0, 0, 0, 1 }; + GdkRGBA *rgba; + GtkAllocation allocation; + + rgba = g_object_get_data (G_OBJECT (widget), "rgba"); + gtk_widget_get_allocation (widget, &allocation); + + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + /* edge outline */ + if (for_shape) + gdk_cairo_set_source_rgba (cr, &shape_color); + else + cairo_set_source_rgba (cr, 0, 0, 0, 0.5); + + rounded_rectangle (cr, + LABEL_WINDOW_EDGE_THICKNESS / 2.0, + LABEL_WINDOW_EDGE_THICKNESS / 2.0, + allocation.width - LABEL_WINDOW_EDGE_THICKNESS, + allocation.height - LABEL_WINDOW_EDGE_THICKNESS, + LABEL_CORNER_RADIUS, LABEL_CORNER_RADIUS); + cairo_set_line_width (cr, LABEL_WINDOW_EDGE_THICKNESS); + cairo_stroke (cr); + + /* fill */ + if (for_shape) { + gdk_cairo_set_source_rgba (cr, &shape_color); + } else { + rgba->alpha = 0.75; + gdk_cairo_set_source_rgba (cr, rgba); + } + + rounded_rectangle (cr, + LABEL_WINDOW_EDGE_THICKNESS, + LABEL_WINDOW_EDGE_THICKNESS, + allocation.width - LABEL_WINDOW_EDGE_THICKNESS * 2, + allocation.height - LABEL_WINDOW_EDGE_THICKNESS * 2, + LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0, + LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0); + cairo_fill (cr); + + cairo_restore (cr); +} + +static void +maybe_update_shape (GtkWidget *widget) +{ + cairo_t *cr; + cairo_surface_t *surface; + cairo_region_t *region; + + /* fallback to XShape only for non-composited clients */ + if (gtk_widget_is_composited (widget)) { + gtk_widget_shape_combine_region (widget, NULL); + return; + } + + surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR_ALPHA, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + cr = cairo_create (surface); + label_draw_background_and_frame (widget, cr, TRUE); + cairo_destroy (cr); + + region = gdk_cairo_region_create_from_surface (surface); + gtk_widget_shape_combine_region (widget, region); + + cairo_surface_destroy (surface); + cairo_region_destroy (region); +} + +static gboolean +label_window_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer data) +{ + if (gtk_widget_is_composited (widget)) { + /* clear any content */ + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_paint (cr); + cairo_restore (cr); + } + + maybe_update_shape (widget); + label_draw_background_and_frame (widget, cr, FALSE); + + return FALSE; +} + +static void +position_window (CcRRLabeler *labeler, + GtkWidget *window, + int x, + int y) +{ + GdkRectangle workarea; + GdkRectangle monitor; + int monitor_num; + + monitor_num = gdk_screen_get_monitor_at_point (labeler->priv->screen, x, y); + gdk_screen_get_monitor_workarea (labeler->priv->screen, monitor_num, &workarea); + gdk_screen_get_monitor_geometry (labeler->priv->screen, + monitor_num, + &monitor); + gdk_rectangle_intersect (&monitor, &workarea, &workarea); + + gtk_window_move (GTK_WINDOW (window), workarea.x, workarea.y); +} + +static void +label_window_realize_cb (GtkWidget *widget) +{ + cairo_region_t *region; + + /* make the whole window ignore events */ + region = cairo_region_create (); + gtk_widget_input_shape_combine_region (widget, region); + cairo_region_destroy (region); + + maybe_update_shape (widget); +} + +static void +label_window_composited_changed_cb (GtkWidget *widget, CcRRLabeler *labeler) +{ + if (gtk_widget_get_realized (widget)) + maybe_update_shape (widget); +} + +static GtkWidget * +create_label_window (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba) +{ + GtkWidget *window; + GtkWidget *widget; + char *str; + const char *display_name; + GdkRGBA black = { 0, 0, 0, 1.0 }; + int x, y; + GdkScreen *screen; + GdkVisual *visual; + + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP); + gtk_window_set_resizable (GTK_WINDOW (window), FALSE); + gtk_widget_set_app_paintable (window, TRUE); + screen = gtk_widget_get_screen (window); + visual = gdk_screen_get_rgba_visual (screen); + + if (visual != NULL) + gtk_widget_set_visual (window, visual); + + gtk_container_set_border_width (GTK_CONTAINER (window), LABEL_WINDOW_PADDING + LABEL_WINDOW_EDGE_THICKNESS); + + /* This is semi-dangerous. The color is part of the labeler->palette + * array. Note that in cc_rr_labeler_finalize(), we are careful to + * free the palette only after we free the windows. + */ + g_object_set_data (G_OBJECT (window), "rgba", rgba); + + g_signal_connect (window, "draw", + G_CALLBACK (label_window_draw_event_cb), labeler); + g_signal_connect (window, "realize", + G_CALLBACK (label_window_realize_cb), labeler); + g_signal_connect (window, "composited-changed", + G_CALLBACK (label_window_composited_changed_cb), labeler); + + if (gnome_rr_config_get_clone (labeler->priv->config)) { + /* Keep this string in sync with gnome-control-center/capplets/display/xrandr-capplet.c:get_display_name() */ + + /* Translators: this is the feature where what you see on your + * laptop's screen is the same as your external projector. + * Here, "Mirrored" is being used as an adjective. For example, + * the Spanish translation could be "Pantallas en Espejo". + */ + display_name = _("Mirrored Displays"); + } else + display_name = gnome_rr_output_info_get_display_name (output); + + str = g_strdup_printf ("%s", display_name); + widget = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL (widget), str); + g_free (str); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_override_color (widget, + gtk_widget_get_state_flags (widget), + &black); + + gtk_container_add (GTK_CONTAINER (window), widget); + + /* Should we center this at the top edge of the monitor, instead of using the upper-left corner? */ + gnome_rr_output_info_get_geometry (output, &x, &y, NULL, NULL); + position_window (labeler, window, x, y); + + gtk_widget_show_all (window); + + return window; +} + +static void +setup_from_config (CcRRLabeler *labeler) +{ + labeler->priv->num_outputs = count_outputs (labeler->priv->config); + + make_palette (labeler); + + cc_rr_labeler_show (labeler); +} + +/** + * cc_rr_labeler_new: + * @config: Configuration of the screens to label + * + * Create a GUI element that will display colored labels on each connected monitor. + * This is useful when users are required to identify which monitor is which, e.g. for + * for configuring multiple monitors. + * The labels will be shown by default, use cc_rr_labeler_hide to hide them. + * + * Returns: A new #CcRRLabeler + */ +CcRRLabeler * +cc_rr_labeler_new (GnomeRRConfig *config) +{ + g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), NULL); + + return g_object_new (GNOME_TYPE_RR_LABELER, "config", config, NULL); +} + +/** + * cc_rr_labeler_show: + * @labeler: A #CcRRLabeler + * + * Show the labels. + */ +void +cc_rr_labeler_show (CcRRLabeler *labeler) +{ + int i; + gboolean created_window_for_clone; + GnomeRROutputInfo **outputs; + + g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); + + if (labeler->priv->windows != NULL) + return; + + labeler->priv->windows = g_new (GtkWidget *, labeler->priv->num_outputs); + + created_window_for_clone = FALSE; + + outputs = gnome_rr_config_get_outputs (labeler->priv->config); + + for (i = 0; i < labeler->priv->num_outputs; i++) { + if (!created_window_for_clone && gnome_rr_output_info_is_active (outputs[i])) { + labeler->priv->windows[i] = create_label_window (labeler, outputs[i], labeler->priv->palette + i); + + if (gnome_rr_config_get_clone (labeler->priv->config)) + created_window_for_clone = TRUE; + } else + labeler->priv->windows[i] = NULL; + } +} + +/** + * cc_rr_labeler_hide: + * @labeler: A #CcRRLabeler + * + * Hide ouput labels. + */ +void +cc_rr_labeler_hide (CcRRLabeler *labeler) +{ + int i; + CcRRLabelerPrivate *priv; + + g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); + + priv = labeler->priv; + + if (priv->windows == NULL) + return; + + for (i = 0; i < priv->num_outputs; i++) + if (priv->windows[i] != NULL) { + gtk_widget_destroy (priv->windows[i]); + priv->windows[i] = NULL; + } + g_free (priv->windows); + priv->windows = NULL; +} + +/** + * cc_rr_labeler_get_rgba_for_output: + * @labeler: A #CcRRLabeler + * @output: Output device (i.e. monitor) to query + * @rgba_out: (out): Color of selected monitor. + * + * Get the color used for the label on a given output (monitor). + */ +void +cc_rr_labeler_get_rgba_for_output (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba_out) +{ + int i; + GnomeRROutputInfo **outputs; + + g_return_if_fail (GNOME_IS_RR_LABELER (labeler)); + g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (output)); + g_return_if_fail (rgba_out != NULL); + + outputs = gnome_rr_config_get_outputs (labeler->priv->config); + + for (i = 0; i < labeler->priv->num_outputs; i++) + if (outputs[i] == output) { + *rgba_out = labeler->priv->palette[i]; + return; + } + + g_warning ("trying to get the color for unknown GnomeOutputInfo %p; returning magenta!", output); + + rgba_out->red = 1.0; + rgba_out->green = 0; + rgba_out->blue = 1.0; + rgba_out->alpha = 1.0; +} diff -Nru gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h --- gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/cc-rr-labeler.h 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,64 @@ +/* gnome-rr-labeler.h - Utility to label monitors to identify them + * while they are being configured. + * + * Copyright 2008, Novell, Inc. + * + * This file is part of the Gnome Library. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Federico Mena-Quintero + */ + +#ifndef CC_RR_LABELER_H +#define CC_RR_LABELER_H + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#define GNOME_TYPE_RR_LABELER (cc_rr_labeler_get_type ()) +#define CC_RR_LABELER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_LABELER, CcRRLabeler)) +#define CC_RR_LABELER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_LABELER, CcRRLabelerClass)) +#define GNOME_IS_RR_LABELER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_LABELER)) +#define GNOME_IS_RR_LABELER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_LABELER)) +#define CC_RR_LABELER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_LABELER, CcRRLabelerClass)) + +typedef struct _CcRRLabeler CcRRLabeler; +typedef struct _CcRRLabelerClass CcRRLabelerClass; +typedef struct _CcRRLabelerPrivate CcRRLabelerPrivate; + +struct _CcRRLabeler { + GObject parent; + + /*< private >*/ + CcRRLabelerPrivate *priv; +}; + +struct _CcRRLabelerClass { + GObjectClass parent_class; +}; + +GType cc_rr_labeler_get_type (void); + +CcRRLabeler *cc_rr_labeler_new (GnomeRRConfig *config); + +void cc_rr_labeler_show (CcRRLabeler *labeler); + +void cc_rr_labeler_hide (CcRRLabeler *labeler); + +void cc_rr_labeler_get_rgba_for_output (CcRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba_out); + +#endif diff -Nru gnome-control-center-3.6.3/panels/display/display-capplet.ui gnome-control-center-3.6.3/panels/display/display-capplet.ui --- gnome-control-center-3.6.3/panels/display/display-capplet.ui 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/display-capplet.ui 2015-02-22 15:27:38.000000000 +0000 @@ -1,6 +1,14 @@ + + + + + + + + @@ -96,56 +104,89 @@ True - 3 + 5 2 12 6 - + + True + 1 + _Resolution + True + resolution_combo + + + + GTK_FILL + + + + + + True + 1 + R_otation + rotation_combo + True + + + + 1 + 2 + GTK_FILL + + + + + True - - - - 1 - 2 2 3 - + 0 + 2 + GTK_FILL - + True 1 - _Resolution + L_auncher placement + launcher_placement_combo True - resolution_combo + 3 + 4 GTK_FILL - + True 1 - R_otation - rotation_combo + S_ticky edges + stickyedge_switch True - 1 - 2 + 4 + 5 GTK_FILL @@ -179,6 +220,63 @@ + + True + False + available_launcher_placement_store + 1 + + + + 0 + + + + + + 1 + + + + + 1 + 2 + 3 + 4 + + + + + + True + 12 + + + True + True + False + True + + + False + False + end + 1 + + + + + 1 + 2 + 4 + 5 + + False + False + 0 + + + diff -Nru gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/gnome-display-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=Screen resolution diff -Nru gnome-control-center-3.6.3/panels/display/Makefile.am gnome-control-center-3.6.3/panels/display/Makefile.am --- gnome-control-center-3.6.3/panels/display/Makefile.am 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/display/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -19,6 +19,8 @@ display-module.c \ cc-display-panel.c \ cc-display-panel.h \ + cc-rr-labeler.c \ + cc-rr-labeler.h \ scrollarea.c \ scrollarea.h \ $(MARSHALFILES) diff -Nru gnome-control-center-3.6.3/panels/info/cc-info-panel.c gnome-control-center-3.6.3/panels/info/cc-info-panel.c --- gnome-control-center-3.6.3/panels/info/cc-info-panel.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/info/cc-info-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -36,6 +36,10 @@ #include #include +#include +#include +#include + #include "hostname-helper.h" #include "gsd-disk-space-helper.h" @@ -301,54 +305,70 @@ } static char * -get_graphics_data_glx_renderer (void) +get_graphics_data_glx_renderer () { - GError *error; - GRegex *re; - GMatchInfo *match_info; - char *output; - char *result; - GString *info; - - info = g_string_new (NULL); - - error = NULL; - g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error); - if (error != NULL) - { - g_warning ("Unable to get graphics info: %s", error->message); - g_error_free (error); - return NULL; - } - - re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error); - if (re == NULL) - { - g_warning ("Error building regex: %s", error->message); - g_error_free (error); - goto out; - } - - g_regex_match (re, output, 0, &match_info); - while (g_match_info_matches (match_info)) - { - char *device; - - device = g_match_info_fetch (match_info, 1); - g_string_append_printf (info, "%s ", device); - g_free (device); + Display *display; + int attributes[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + None + }; + int nconfigs; + int major, minor; + Window window; + GLXFBConfig *config; + GLXWindow glxwin; + GLXContext context; + XSetWindowAttributes win_attributes; + XVisualInfo *visualInfo; + char *renderer; + + gdk_error_trap_push (); + + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + + glXQueryVersion (display, &major, &minor); + config = glXChooseFBConfig (display, DefaultScreen (display), + attributes, &nconfigs); + if (config == NULL) { + g_warning ("Failed to get OpenGL configuration"); - g_match_info_next (match_info, NULL); - } - g_match_info_free (match_info); - g_regex_unref (re); + gdk_error_trap_pop_ignored (); + return NULL; + } + visualInfo = glXGetVisualFromFBConfig (display, *config); + win_attributes.colormap = XCreateColormap (display, DefaultRootWindow(display), + visualInfo->visual, AllocNone ); + + window = XCreateWindow (display, DefaultRootWindow (display), + 0, 0, /* x, y */ + 1, 1, /* width, height */ + 0, /* border_width */ + visualInfo->depth, InputOutput, + visualInfo->visual, CWColormap, &win_attributes); + glxwin = glXCreateWindow (display, *config, window, NULL); + + context = glXCreateNewContext (display, *config, GLX_RGBA_TYPE, + NULL, TRUE); + XFree (config); + + glXMakeContextCurrent (display, glxwin, glxwin, context); + renderer = (char *) glGetString (GL_RENDERER); + renderer = renderer ? prettify_info (renderer) : NULL; + + glXMakeContextCurrent (display, None, None, NULL); + glXDestroyContext (display, context); + glXDestroyWindow (display, glxwin); + XDestroyWindow (display, window); + XFree (visualInfo); - out: - g_free (output); - result = prettify_info (info->str); - g_string_free (info, TRUE); + if (gdk_error_trap_pop () != Success) { + g_warning ("Failed to get OpenGL driver info"); + return NULL; + } - return result; + return renderer; } static char * @@ -1737,6 +1757,8 @@ g_free (text); } + gtk_widget_hide (WID ("version_label")); + glibtop_get_mem (&mem); text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS); widget = WID ("memory_label"); @@ -1931,7 +1953,7 @@ { GError *error; error = NULL; - g_spawn_command_line_async ("gpk-update-viewer", &error); + g_spawn_command_line_async ("update-manager", &error); if (error != NULL) { g_warning ("unable to launch Software Updates: %s", error->message); diff -Nru gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/info/gnome-info-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=info diff -Nru gnome-control-center-3.6.3/panels/info/info.ui gnome-control-center-3.6.3/panels/info/info.ui --- gnome-control-center-3.6.3/panels/info/info.ui 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/info/info.ui 2015-02-22 15:27:38.000000000 +0000 @@ -239,7 +239,7 @@ True False - GnomeLogoVerticalMedium.svg + UbuntuLogo.png False @@ -1196,7 +1196,7 @@ - True + False False 1 Forced _Fallback Mode @@ -1245,7 +1245,7 @@ - True + False False start center diff -Nru gnome-control-center-3.6.3/panels/info/logo-generator.vala gnome-control-center-3.6.3/panels/info/logo-generator.vala --- gnome-control-center-3.6.3/panels/info/logo-generator.vala 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/info/logo-generator.vala 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,47 @@ +public class Main : Object +{ + + private static string? file = null; + private static string? text = null; + private static string? result = null; + private const OptionEntry[] options = { + {"logo", 0, 0, OptionArg.FILENAME, ref file, "Path to logo", "LOGO"}, + {"text", 0, 0, OptionArg.STRING, ref text, "Sublogo text", "TEXT"}, + {"output", 0, 0, OptionArg.FILENAME, ref result, "Path to rendered output", "OUTPUT"}, + {null} + }; + + public static int main(string[] args) { + try { + var opt_context = new OptionContext ("- OptionContext example"); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + opt_context.parse (ref args); + } catch (OptionError e) { + stdout.printf ("error: %s\n", e.message); + stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]); + return 0; + } + Cairo.ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 190, 145); + Cairo.Context context = new Cairo.Context (surface); + Cairo.ImageSurface logo = new Cairo.ImageSurface.from_png (file); + context.set_source_surface (logo, 0, 0); + context.paint(); + + context.set_source_rgba (0, 0, 0, 1); + context.translate (0, 117); + var font_description = new Pango.FontDescription(); + font_description.set_family("Ubuntu"); + font_description.set_size((int)(17.5 * Pango.SCALE)); + var layout = Pango.cairo_create_layout (context); + layout.set_alignment(Pango.Alignment.CENTER); + layout.set_width(190*Pango.SCALE); + layout.set_font_description (font_description); + layout.set_text (text, -1); + + Pango.cairo_show_layout(context, layout); + + surface.write_to_png(result); + return 0; + } +} diff -Nru gnome-control-center-3.6.3/panels/info/Makefile.am gnome-control-center-3.6.3/panels/info/Makefile.am --- gnome-control-center-3.6.3/panels/info/Makefile.am 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/info/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -10,11 +10,22 @@ -DLIBEXECDIR="\"$(libexecdir)\"" \ $(NULL) -noinst_PROGRAMS = test-hostname +noinst_PROGRAMS = test-hostname logo-generator test_hostname_SOURCES = hostname-helper.c hostname-helper.h test-hostname.c test_hostname_LDADD = $(PANEL_LIBS) $(INFO_PANEL_LIBS) test_hostname_CFLAGS = $(INCLUDES) +logo_generator_SOURCES = logo-generator.vala + +logo_generator_VALAFLAGS = \ + --pkg cairo \ + --pkg pango \ + --pkg pangocairo \ + --target-glib 2.32 + +logo_generator_CFLAGS = $(PANEL_CFLAGS) $(INFO_PANEL_CFLAGS) +logo_generator_LDADD = $(PANEL_LIBS) $(INFO_PANEL_LIBS) + all-local: check-local check-local: test-hostname diff -Nru gnome-control-center-3.6.3/panels/keyboard/01-input-sources.xml.in gnome-control-center-3.6.3/panels/keyboard/01-input-sources.xml.in --- gnome-control-center-3.6.3/panels/keyboard/01-input-sources.xml.in 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/01-input-sources.xml.in 2015-02-22 15:27:39.000000000 +0000 @@ -1,6 +1,6 @@ + + diff -Nru gnome-control-center-3.6.3/panels/keyboard/01-screenshot.xml.in gnome-control-center-3.6.3/panels/keyboard/01-screenshot.xml.in --- gnome-control-center-3.6.3/panels/keyboard/01-screenshot.xml.in 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/01-screenshot.xml.in 2015-02-22 15:27:39.000000000 +0000 @@ -1,17 +1,14 @@ - + _description="Take a screenshot"/> - + _description="Take a screenshot of a window"/> - + _description="Take a screenshot of an area"/> diff -Nru gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c --- gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-item.c 2015-02-22 15:27:38.000000000 +0000 @@ -143,14 +143,25 @@ const char *value, gboolean set_backend) { + /* don't reassign or key in the callback to the binding itself (as it's invalid for the cell renderer) */ + if ((g_strcmp0 (value, "") == 0) || (g_strcmp0 (value, "") == 0)) + return; + g_free (item->binding); item->binding = g_strdup (value); binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); + const char *key; + char *cheated_modifier = NULL; + if (g_strcmp0 (item->binding, "Alt_L") == 0) + cheated_modifier = g_strdup_printf ("<%s>", item->binding); + if (set_backend == FALSE) return; - settings_set_binding (item->settings, item->key, item->binding); + settings_set_binding (item->settings, item->key, cheated_modifier ? cheated_modifier: item->binding); + + g_free (cheated_modifier); } const char * @@ -441,6 +452,13 @@ item->settings = g_settings_new (item->schema); item->binding = settings_get_binding (item->settings, item->key); item->editable = g_settings_is_writable (item->settings, item->key); + + if ((g_strcmp0 (item->binding, "") == 0) || (g_strcmp0 (item->binding, "") == 0)) + { + g_free (item->binding); + item->binding = g_strdup ("Alt_L"); + } + binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); signal_name = g_strdup_printf ("changed::%s", item->key); diff -Nru gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-option.c gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-option.c --- gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-option.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/cc-keyboard-option.c 2015-02-22 15:27:38.000000000 +0000 @@ -38,6 +38,7 @@ #define XKB_OPTION_GROUP_LVL3 "lv3" #define XKB_OPTION_GROUP_COMP "Compose key" +#define XKB_OPTION_GROUP_GRP "grp" enum { @@ -96,6 +97,32 @@ NULL }; +/* This list must be kept in sync with what mutter is able to + * handle. */ +static const gchar *xkb_option_grp_whitelist[] = { + "grp:toggle", + "grp:lalt_toggle", + "grp:lwin_toggle", + "grp:rwin_toggle", + "grp:lshift_toggle", + "grp:rshift_toggle", + "grp:lctrl_toggle", + "grp:rctrl_toggle", + "grp:sclk_toggle", + "grp:menu_toggle", + "grp:caps_toggle", + "grp:shift_caps_toggle", + "grp:alt_caps_toggle", + "grp:alt_space_toggle", + "grp:ctrl_shift_toggle", + "grp:lctrl_lshift_toggle", + "grp:rctrl_rshift_toggle", + "grp:ctrl_alt_toggle", + "grp:alt_shift_toggle", + "grp:lalt_lshift_toggle", + NULL +}; + static GList *objects_list = NULL; GType cc_keyboard_option_get_type (void); @@ -232,6 +259,8 @@ self->whitelist = xkb_option_lvl3_whitelist; else if (g_str_equal (self->group, XKB_OPTION_GROUP_COMP)) self->whitelist = xkb_option_comp_whitelist; + else if (g_str_equal (self->group, XKB_OPTION_GROUP_GRP)) + self->whitelist = xkb_option_grp_whitelist; else g_assert_not_reached (); @@ -319,6 +348,11 @@ "group", XKB_OPTION_GROUP_COMP, "description", _("Compose Key"), NULL)); + objects_list = g_list_prepend (objects_list, + g_object_new (CC_TYPE_KEYBOARD_OPTION, + "group", XKB_OPTION_GROUP_GRP, + "description", _("Modifiers-only switch to next source"), + NULL)); return objects_list; } diff -Nru gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/gnome-keyboard-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=keyboard diff -Nru gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c --- gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/keyboard/keyboard-shortcuts.c 2015-02-22 15:27:38.000000000 +0000 @@ -1716,7 +1716,7 @@ gtk_tree_view_append_column (treeview, column); renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, - "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, + "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_MODIFIER_TAP, NULL); g_signal_connect (treeview, "button_press_event", diff -Nru gnome-control-center-3.6.3/panels/mouse/cc-mouse-panel.c gnome-control-center-3.6.3/panels/mouse/cc-mouse-panel.c --- gnome-control-center-3.6.3/panels/mouse/cc-mouse-panel.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/mouse/cc-mouse-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -107,7 +107,10 @@ static const char * cc_mouse_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/mouse"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/mouse"; + else + return "help:gnome-help/mouse"; } static void diff -Nru gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/mouse/gnome-mouse-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=mouse diff -Nru gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.c gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.c --- gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.c 2015-02-22 15:27:39.000000000 +0000 @@ -181,6 +181,9 @@ g_signal_connect (WID ("pointer_speed_scale"), "value-changed", G_CALLBACK (pointer_speed_scale_event), dialog); + g_settings_bind (mouse_settings, "motion-acceleration", + gtk_range_get_adjustment (GTK_RANGE (WID ("pointer_speed_scale"))), "value", + G_SETTINGS_BIND_DEFAULT); /* Trackpad page */ touchpad_present = touchpad_is_present (); @@ -202,6 +205,9 @@ g_settings_bind (touchpad_settings, "natural-scroll", WID ("natural_scroll_toggle"), "active", G_SETTINGS_BIND_DEFAULT); + g_settings_bind (touchpad_settings, "motion-acceleration", + gtk_range_get_adjustment (GTK_RANGE (WID ("touchpad_pointer_speed_scale"))), "value", + G_SETTINGS_BIND_DEFAULT); g_signal_connect (WID ("touchpad_pointer_speed_scale"), "value-changed", G_CALLBACK (pointer_speed_scale_event), dialog); diff -Nru gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.ui gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.ui --- gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.ui 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/mouse/gnome-mouse-properties.ui 2015-02-22 15:27:39.000000000 +0000 @@ -655,7 +655,7 @@ - C_ontent sticks to fingers + _Natural scrolling False True True diff -Nru gnome-control-center-3.6.3/panels/network/cc-network-panel.c gnome-control-center-3.6.3/panels/network/cc-network-panel.c --- gnome-control-center-3.6.3/panels/network/cc-network-panel.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/cc-network-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -242,7 +242,10 @@ static const char * cc_network_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/net"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/net"; + else + return "help:gnome-help/net"; } static void diff -Nru gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/gnome-network-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=network diff -Nru gnome-control-center-3.6.3/panels/network/net-device-wifi.c gnome-control-center-3.6.3/panels/network/net-device-wifi.c --- gnome-control-center-3.6.3/panels/network/net-device-wifi.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/net-device-wifi.c 2015-02-22 15:27:39.000000000 +0000 @@ -150,7 +150,7 @@ ssid = nm_access_point_get_ssid (ap); if (ssid == NULL) return; - ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); + ssid_text = nm_utils_ssid_to_utf8 (ssid); title = g_markup_escape_text (ssid_text, -1); is_active_ap = active && nm_utils_same_ssid (ssid, nm_access_point_get_ssid (active), TRUE); @@ -172,6 +172,7 @@ COLUMN_AP_OUT_OF_RANGE, FALSE, COLUMN_AP_IS_SAVED, FALSE, -1); + g_free (ssid_text); g_free (title); } @@ -531,7 +532,7 @@ return; ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (setting)); - ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); + ssid_text = nm_utils_ssid_to_utf8 (ssid); title = g_markup_escape_text (ssid_text, -1); g_debug ("got saved %s", title); @@ -559,6 +560,7 @@ COLUMN_AP_IS_SAVED, TRUE, -1); g_free (title); + g_free (ssid_text); } static void @@ -1074,7 +1076,7 @@ const gchar *ap_object_path) { const GByteArray *ssid; - const gchar *ssid_tmp; + const gchar *ssid_tmp = NULL; GSList *list, *l; GSList *filtered; NMConnection *connection_activate = NULL; @@ -1112,15 +1114,18 @@ ssid = nm_setting_wireless_get_ssid (setting_wireless); if (ssid == NULL) continue; - ssid_tmp = nm_utils_escape_ssid (ssid->data, ssid->len); + ssid_tmp = nm_utils_ssid_to_utf8 (ssid); if (g_strcmp0 (ssid_target, ssid_tmp) == 0) { g_debug ("we found an existing connection %s to activate!", nm_connection_get_id (connection)); connection_activate = connection; break; } + g_free (ssid_tmp); + ssid_tmp = NULL; } + g_free (ssid_tmp); g_slist_free (list); g_slist_free (filtered); diff -Nru gnome-control-center-3.6.3/panels/network/net-proxy.c gnome-control-center-3.6.3/panels/network/net-proxy.c --- gnome-control-center-3.6.3/panels/network/net-proxy.c 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/net-proxy.c 2015-02-22 15:27:39.000000000 +0000 @@ -25,8 +25,14 @@ #include #include +#include +#include +#include + #include "net-proxy.h" + + #define NET_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NET_TYPE_PROXY, NetProxyPrivate)) struct _NetProxyPrivate @@ -250,6 +256,148 @@ g_type_class_add_private (klass, sizeof (NetProxyPrivate)); } + +static gboolean +ubuntu_is_in_admin_group (int id_group) +{ + gid_t groups [1024]; + int i, ngroups; + + ngroups = getgroups (1024, groups); + if (ngroups < 0) { + perror ("getgroups"); + return FALSE; + } + + for (i = 0; i < ngroups; ++i) { + if (groups[i] == id_group) + return TRUE; + } + + return FALSE; +} + +static gboolean +ubuntu_is_admin () +{ + struct group *admin_group; + + admin_group = getgrnam ("admin"); + if (admin_group != NULL && ubuntu_is_in_admin_group (admin_group->gr_gid)) + return TRUE; + + admin_group = getgrnam ("sudo"); + if (admin_group != NULL && ubuntu_is_in_admin_group (admin_group->gr_gid)) + return TRUE; + + return FALSE; +} + +static void +ubuntu_reset_system_proxy (GDBusProxy *proxy, const gchar *protocol) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (proxy, "set_proxy", + g_variant_new ("(ss)", protocol, ""), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (result) + g_variant_unref (result); + else { + g_warning ("Error while calling set_proxy for %s protocol: %s", protocol, error->message); + g_error_free (error); + } +} + +static void +ubuntu_set_proxy_for_protocol (GDBusProxy *proxy, const gchar *protocol, GSettings *settings) +{ + GVariant *result; + gchar *proxy_str, *host; + GError *error = NULL; + gint port; + + host = g_settings_get_string (settings, "host"); + port = g_settings_get_int (settings, "port"); + + if (host && *host == '\0') { + ubuntu_reset_system_proxy (proxy, protocol); + } else { + proxy_str = g_strdup_printf ("%s://%s:%i/", protocol, host, port); + + result = g_dbus_proxy_call_sync (proxy, "set_proxy", + g_variant_new ("(ss)", protocol, proxy_str), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (result) + g_variant_unref (result); + else { + g_warning ("Error while calling set_proxy for %s protocol: %s", protocol, error->message); + g_error_free (error); + } + g_free (proxy_str); + } + + /* Free memory */ + g_free (host); + g_object_unref (settings); +} + +static void +ubuntu_on_proxy_apply_system_settings (GtkButton *button, gpointer user_data) +{ + GDBusConnection *bus; + GDBusProxy *dbus_proxy; + GError *error; + GDesktopProxyMode proxy_mode; + NetProxy *proxy = NET_PROXY (user_data); + + error = NULL; + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!bus) { + g_warning ("Could not retrieve system bus: %s", error->message); + g_error_free (error); + + return; + } + + dbus_proxy = g_dbus_proxy_new_sync (bus, 0, NULL, + "com.ubuntu.SystemService", + "/", + "com.ubuntu.SystemService", + NULL, + &error); + if (!dbus_proxy) { + g_warning ("Could not retrieve bus object: %s", error->message); + g_error_free (error); + + return; + } + + /* Retrieve the current settings */ + proxy_mode = g_settings_get_enum (proxy->priv->settings, "mode"); + switch (proxy_mode) { + case G_DESKTOP_PROXY_MODE_AUTO: + case G_DESKTOP_PROXY_MODE_NONE: + ubuntu_reset_system_proxy (dbus_proxy, "http"); + ubuntu_reset_system_proxy (dbus_proxy, "https"); + ubuntu_reset_system_proxy (dbus_proxy, "ftp"); + ubuntu_reset_system_proxy (dbus_proxy, "socks"); + break; + case G_DESKTOP_PROXY_MODE_MANUAL: + ubuntu_set_proxy_for_protocol (dbus_proxy, "http", g_settings_get_child (proxy->priv->settings, "http")); + ubuntu_set_proxy_for_protocol (dbus_proxy, "https", g_settings_get_child (proxy->priv->settings, "https")); + ubuntu_set_proxy_for_protocol (dbus_proxy, "ftp", g_settings_get_child (proxy->priv->settings, "ftp")); + ubuntu_set_proxy_for_protocol (dbus_proxy, "socks", g_settings_get_child (proxy->priv->settings, "socks")); + break; + } + + /* Free memory */ + g_object_unref (dbus_proxy); +} + static void net_proxy_init (NetProxy *proxy) { @@ -369,6 +517,13 @@ "label_proxy_status")); gtk_label_set_label (GTK_LABEL (widget), ""); + /* Ubuntu button for system proxy settings */ + if (ubuntu_is_admin ()) { + g_signal_connect (G_OBJECT (gtk_builder_get_object (proxy->priv->builder, "system_proxy_button")), "clicked", + G_CALLBACK (ubuntu_on_proxy_apply_system_settings), proxy); + } else + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, "system_proxy_button"))); + /* hide the switch until we get some more detail in the mockup */ widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, "device_proxy_off_switch")); diff -Nru gnome-control-center-3.6.3/panels/network/network-proxy.ui gnome-control-center-3.6.3/panels/network/network-proxy.ui --- gnome-control-center-3.6.3/panels/network/network-proxy.ui 2012-11-14 11:42:43.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/network-proxy.ui 2015-02-22 15:27:39.000000000 +0000 @@ -280,6 +280,21 @@ + + Apply system wide + True + True + True + False + + + 0 + 7 + 3 + 1 + + + True False @@ -290,7 +305,7 @@ 0 - 7 + 8 3 1 diff -Nru gnome-control-center-3.6.3/panels/network/rfkill-glib.c gnome-control-center-3.6.3/panels/network/rfkill-glib.c --- gnome-control-center-3.6.3/panels/network/rfkill-glib.c 2012-11-09 10:50:23.000000000 +0000 +++ gnome-control-center-3.6.3/panels/network/rfkill-glib.c 2015-02-22 15:27:38.000000000 +0000 @@ -80,7 +80,7 @@ case RFKILL_TYPE_WWAN: return "WWAN"; default: - g_assert_not_reached (); + return "UNKNOWN"; } } diff -Nru gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c --- gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-model.c 2015-02-22 15:27:39.000000000 +0000 @@ -330,8 +330,8 @@ icon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error); if (icon == NULL) { - goa_warning ("Error creating GIcon for account: %s (%s, %d)", - error->message, g_quark_to_string (error->domain), error->code); + g_warning ("Error creating GIcon for account: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); } @@ -370,7 +370,7 @@ GtkTreeIter iter; if (!find_iter_for_object (model, object, &iter)) { - goa_warning ("Error removing object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + g_warning ("Error removing object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); } else { @@ -385,7 +385,7 @@ GtkTreeIter iter; if (!find_iter_for_object (model, object, &iter)) { - goa_warning ("Error updating object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + g_warning ("Error updating object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); } else { diff -Nru gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c --- gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/online-accounts/cc-online-accounts-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -147,8 +147,8 @@ GNOMECC_UI_DIR "/online-accounts.ui", &error) == 0) { - goa_warning ("Error loading UI file: %s (%s, %d)", - error->message, g_quark_to_string (error->domain), error->code); + g_warning ("Error loading UI file: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); goto out; } @@ -189,8 +189,8 @@ panel->client = goa_client_new_sync (NULL /* GCancellable */, &error); if (panel->client == NULL) { - goa_warning ("Error getting a GoaClient: %s (%s, %d)", - error->message, g_quark_to_string (error->domain), error->code); + g_warning ("Error getting a GoaClient: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); gtk_widget_set_sensitive (w, FALSE); g_error_free (error); @@ -256,7 +256,10 @@ static const char * goa_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/accounts"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/accounts"; + else + return "help:gnome-help/accounts"; } static void @@ -596,9 +599,17 @@ /* ---------------------------------------------------------------------------------------------------- */ +typedef struct +{ + GoaPanel *panel; +} AddAccountData; + static void -add_account (GoaPanel *panel) +get_all_providers_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { + AddAccountData *data = user_data; GtkWindow *parent; GtkWidget *dialog; gint response; @@ -609,12 +620,15 @@ providers = NULL; - parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); + providers = NULL; + if (!goa_provider_get_all_finish (&providers, res, NULL)) + goto out; + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (data->panel)))); - dialog = goa_panel_add_account_dialog_new (panel->client); + dialog = goa_panel_add_account_dialog_new (data->panel->client); gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); - providers = goa_provider_get_all (); for (l = providers; l != NULL; l = l->next) { GoaProvider *provider; @@ -643,11 +657,11 @@ { GtkTreeIter iter; /* navigate to newly created object */ - if (goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, + if (goa_panel_accounts_model_get_iter_for_object (data->panel->accounts_model, object, &iter)) { - gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->panel->accounts_treeview)), &iter); } g_object_unref (object); @@ -675,6 +689,18 @@ out: g_list_foreach (providers, (GFunc) g_object_unref, NULL); g_list_free (providers); + g_clear_object (&data->panel); + g_slice_free (AddAccountData, data); +} + +static void +add_account (GoaPanel *panel) +{ + AddAccountData *data; + + data = g_slice_new0 (AddAccountData); + data->panel = g_object_ref_sink (panel); + goa_provider_get_all (get_all_providers_cb, data); } /* ---------------------------------------------------------------------------------------------------- */ diff -Nru gnome-control-center-3.6.3/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in gnome-control-center-3.6.3/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 2015-02-22 15:27:38.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=Online Accounts diff -Nru gnome-control-center-3.6.3/panels/power/cc-power-panel.c gnome-control-center-3.6.3/panels/power/cc-power-panel.c --- gnome-control-center-3.6.3/panels/power/cc-power-panel.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/power/cc-power-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -39,6 +39,7 @@ { GSettings *lock_settings; GSettings *gsd_settings; + GSettings *power_settings; GCancellable *cancellable; GtkBuilder *builder; GDBusProxy *proxy; @@ -89,6 +90,11 @@ g_object_unref (priv->gsd_settings); priv->gsd_settings = NULL; } + if (priv->power_settings) + { + g_object_unref (priv->power_settings); + priv->power_settings = NULL; + } if (priv->cancellable != NULL) { g_cancellable_cancel (priv->cancellable); @@ -124,7 +130,10 @@ static const char * cc_power_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/power"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/power"; + else + return "help:gnome-help/power"; } static void @@ -932,6 +941,7 @@ set_ac_battery_ui_mode (CcPowerPanel *self) { gboolean has_batteries = FALSE; + gboolean has_lid = FALSE; gboolean ret; GError *error = NULL; GPtrArray *devices; @@ -964,7 +974,13 @@ } } g_ptr_array_unref (devices); + + has_lid = up_client_get_lid_is_present (self->priv->up_client); + out: + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_ac"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_lid_action"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_battery"), has_batteries && has_lid); gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); @@ -1020,7 +1036,7 @@ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, - "org.gnome.SettingsDaemon", + "org.gnome.SettingsDaemon.Power", "/org/gnome/SettingsDaemon/Power", "org.gnome.SettingsDaemon.Power", self->priv->cancellable, @@ -1080,8 +1096,59 @@ G_CALLBACK (activate_link_cb), self); + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-ac-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_ac")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-ac-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_battery")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + widget = WID (self->priv->builder, "vbox_power"); gtk_widget_reparent (widget, (GtkWidget *) self); + + /* Set up Unity-specific controls */ + /* References: + * https://wiki.ubuntu.com/Power + * https://docs.google.com/document/d/1ILTJDiDCd25Npt2AmgzF8aOnZZECxTfM0hvsbWT2BxA/edit?pli=1#heading=h.i5lg1g344bsb + */ + // First check the schema is installed + GSettingsSchemaSource *schema_source = g_settings_schema_source_ref ( + g_settings_schema_source_get_default ()); + GSettingsSchema *schema = g_settings_schema_source_lookup ( + schema_source, + "com.canonical.indicator.power", + TRUE); + g_settings_schema_source_unref (schema_source); + + if (schema) + { + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_indicator")); + self->priv->power_settings = g_settings_new ("com.canonical.indicator.power"); + g_settings_bind (self->priv->power_settings, "icon-policy", + widget, "active-id", G_SETTINGS_BIND_DEFAULT); + g_settings_schema_unref (schema); + } + else + { + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "separator_indicator"))); + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "label_indicator"))); + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "combobox_indicator"))); + } + } void diff -Nru gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/power/gnome-power-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;HardwareSettings -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=power diff -Nru gnome-control-center-3.6.3/panels/power/power.ui gnome-control-center-3.6.3/panels/power/power.ui --- gnome-control-center-3.6.3/panels/power/power.ui 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/power/power.ui 2015-02-22 15:27:39.000000000 +0000 @@ -40,6 +40,10 @@ 600 + 20 minutes + 1200 + + 30 minutes 1800 @@ -48,11 +52,59 @@ 3600 + 2 hours + 7200 + + Don't suspend 0 + + + + + + + + + + + + Suspend + 1 + True + + + Do nothing + 5 + True + + + + + + + + + + + + + When battery is present + present + + + When battery is charging/in use + charge + + + Never + never + + + False False @@ -172,6 +224,92 @@ 2 + + + True + False + end + When the lid is closed + + + 0 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 1 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 2 + 3 + + + + + True + False + + + 0 + 4 + 4 + 1 + + + + + True + False + end + Show battery status in the _menu bar + True + + + 0 + 5 + + + + + True + False + liststore_indicator + True + + + + + + 1 + 5 + 2 + 1 + + False @@ -352,9 +490,12 @@ + + + diff -Nru gnome-control-center-3.6.3/panels/printers/cc-printers-panel.c gnome-control-center-3.6.3/panels/printers/cc-printers-panel.c --- gnome-control-center-3.6.3/panels/printers/cc-printers-panel.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/printers/cc-printers-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -251,7 +251,10 @@ static const char * cc_printers_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/printing"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/printing"; + else + return "help:gnome-help/printing"; } static void diff -Nru gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in 2012-11-05 08:38:42.000000000 +0000 +++ gnome-control-center-3.6.3/panels/printers/gnome-printers-panel.desktop.in.in 2015-02-22 15:27:38.000000000 +0000 @@ -8,7 +8,7 @@ StartupNotify=true # The X-GNOME-Settings-Panel is necessary to show in the main shell UI Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Settings-Panel=printers # Translators: those are keywords for the printing control-center panel _Keywords=Printer;Queue;Print;Paper;Ink;Toner; diff -Nru gnome-control-center-3.6.3/panels/printers/pp-new-printer.c gnome-control-center-3.6.3/panels/printers/pp-new-printer.c --- gnome-control-center-3.6.3/panels/printers/pp-new-printer.c 2012-10-01 09:38:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/printers/pp-new-printer.c 2015-02-22 15:27:39.000000000 +0000 @@ -686,6 +686,7 @@ GDBusConnection *bus; GVariantBuilder array_builder; GVariant *output; + gboolean cancelled = FALSE; PPDName *ppd_item = NULL; GError *error = NULL; @@ -701,15 +702,15 @@ } else { - if (error->domain != G_IO_ERROR || - error->code != G_IO_ERROR_CANCELLED) + cancelled = g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + + if (!cancelled) g_warning ("%s", error->message); - g_error_free (error); + + g_clear_error (&error); } - if (!error || - error->domain != G_IO_ERROR || - error->code != G_IO_ERROR_CANCELLED) + if (!cancelled) { if (ppd_item == NULL || ppd_item->ppd_match_level < PPD_EXACT_MATCH) { diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in 2012-11-05 08:38:42.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=region diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c --- gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c 2011-10-03 13:32:59.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-formats.c 2015-02-22 15:27:38.000000000 +0000 @@ -31,6 +31,7 @@ #include "cc-language-chooser.h" #include "gdm-languages.h" #include "gnome-region-panel-formats.h" +#include "gnome-region-panel-system.h" static void display_date (GtkLabel *label, GDateTime *dt, const gchar *format) @@ -149,6 +150,46 @@ g_free (active_id); } +static void +set_formats_locale (const gchar *formats_locale) +{ + GDBusProxy *proxy; + GError *error = NULL; + gchar *user_path; + GVariant *ret; + + user_path = g_strdup_printf ("/org/freedesktop/Accounts/User%i", getuid ()); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + user_path, + "org.freedesktop.Accounts.User", + NULL, + &error); + if (!proxy) { + g_warning ("Couldn't get accountsservice proxy for %s: %s", user_path, error->message); + g_error_free (error); + g_free (user_path); + return; + } + + ret = g_dbus_proxy_call_sync (proxy, + "SetFormatsLocale", + g_variant_new ("(s)", formats_locale), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!ret) { + g_warning ("Couldn't set FormatsLocale: %s", error->message); + g_error_free (error); + } else + g_variant_unref (ret); + + g_object_unref (proxy); + g_free (user_path); +} static void update_settings_cb (GtkTreeSelection *selection, gpointer user_data) @@ -159,7 +200,6 @@ gchar *active_id; GtkWidget *treeview; GSettings *locale_settings; - gchar *current_setting; if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { return; @@ -169,13 +209,10 @@ treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector")); locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); - current_setting = g_settings_get_string (locale_settings, "region"); - if (g_strcmp0 (active_id, current_setting) != 0) { - g_settings_set_string (locale_settings, "region", active_id); - } + set_formats_locale (active_id); + locale_settings_changed (locale_settings, NULL, builder); - g_free (current_setting); g_free (active_id); } @@ -184,7 +221,7 @@ { gchar *current_setting; - current_setting = g_settings_get_string (locale_settings, "region"); + current_setting = cc_common_language_get_property ("FormatsLocale"); select_region (treeview, current_setting); g_free (current_setting); } @@ -213,7 +250,6 @@ populate_regions (GtkBuilder *builder, const gchar *current_lang) { gchar *current_region; - GSettings *locale_settings; GHashTable *ht; GHashTableIter htiter; GtkTreeModel *model; @@ -228,11 +264,10 @@ g_signal_handlers_block_by_func (selection, update_settings_cb, builder); model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); - locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); ht = cc_common_language_get_initial_regions (current_lang); - current_region = g_settings_get_string (locale_settings, "region"); + current_region = cc_common_language_get_property ("FormatsLocale"); if (!current_region || !current_region[0]) { current_region = g_strdup (current_lang); } diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c --- gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-input.c 2015-02-22 15:27:39.000000000 +0000 @@ -65,218 +65,6 @@ static GCancellable *ibus_cancellable = NULL; static guint shell_name_watch_id = 0; -static const gchar *supported_ibus_engines[] = { - /* Simplified Chinese */ - "pinyin", - "bopomofo", - "wubi", - "erbi", - /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ - "libpinyin", - "libbopomofo", - - /* Traditional Chinese */ - /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ - "chewing", - "cangjie5", - "cangjie3", - "quick5", - "quick3", - "stroke5", - - /* Japanese */ - "anthy", - "mozc-jp", - "skk", - - /* Korean */ - "hangul", - - /* Thai */ - "m17n:th:kesmanee", - "m17n:th:pattachote", - "m17n:th:tis820", - - /* Vietnamese */ - "m17n:vi:tcvn", - "m17n:vi:telex", - "m17n:vi:viqr", - "m17n:vi:vni", - "Unikey", - - /* Sinhala */ - "m17n:si:wijesekera", - "m17n:si:phonetic-dynamic", - "m17n:si:trans", - "sayura", - - /* Indic */ - /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ - - /* Assamese */ - "m17n:as:phonetic", - "m17n:as:inscript", - "m17n:as:itrans", - - /* Bengali */ - "m17n:bn:inscript", - "m17n:bn:itrans", - "m17n:bn:probhat", - - /* Gujarati */ - "m17n:gu:inscript", - "m17n:gu:itrans", - "m17n:gu:phonetic", - - /* Hindi */ - "m17n:hi:inscript", - "m17n:hi:itrans", - "m17n:hi:phonetic", - "m17n:hi:remington", - "m17n:hi:typewriter", - "m17n:hi:vedmata", - - /* Kannada */ - "m17n:kn:kgp", - "m17n:kn:inscript", - "m17n:kn:itrans", - - /* Kashmiri */ - "m17n:ks:inscript", - - /* Maithili */ - "m17n:mai:inscript", - - /* Malayalam */ - "m17n:ml:inscript", - "m17n:ml:itrans", - "m17n:ml:mozhi", - "m17n:ml:swanalekha", - - /* Marathi */ - "m17n:mr:inscript", - "m17n:mr:itrans", - "m17n:mr:phonetic", - - /* Nepali */ - "m17n:ne:rom", - "m17n:ne:trad", - - /* Oriya */ - "m17n:or:inscript", - "m17n:or:itrans", - "m17n:or:phonetic", - - /* Punjabi */ - "m17n:pa:inscript", - "m17n:pa:itrans", - "m17n:pa:phonetic", - "m17n:pa:jhelum", - - /* Sanskrit */ - "m17n:sa:harvard-kyoto", - - /* Sindhi */ - "m17n:sd:inscript", - - /* Tamil */ - "m17n:ta:tamil99", - "m17n:ta:inscript", - "m17n:ta:itrans", - "m17n:ta:phonetic", - "m17n:ta:lk-renganathan", - "m17n:ta:vutam", - "m17n:ta:typewriter", - - /* Telugu */ - "m17n:te:inscript", - "m17n:te:apple", - "m17n:te:pothana", - "m17n:te:rts", - - /* Urdu */ - "m17n:ur:phonetic", - - /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ - "m17n:as:inscript2", - "m17n:bn:inscript2", - "m17n:brx:inscript2-deva", - "m17n:doi:inscript2-deva", - "m17n:gu:inscript2", - "m17n:hi:inscript2", - "m17n:kn:inscript2", - "m17n:kok:inscript2-deva", - "m17n:mai:inscript2", - "m17n:ml:inscript2", - "m17n:mni:inscript2-beng", - "m17n:mni:inscript2-mtei", - "m17n:mr:inscript2", - "m17n:ne:inscript2-deva", - "m17n:or:inscript2", - "m17n:pa:inscript2-guru", - "m17n:sa:inscript2", - "m17n:sat:inscript2-deva", - "m17n:sat:inscript2-olck", - "m17n:sd:inscript2-deva", - "m17n:ta:inscript2", - "m17n:te:inscript2", - - /* No corresponding XKB map available for the languages */ - - /* Chinese Yi */ - "m17n:ii:phonetic", - - /* Tai-Viet */ - "m17n:tai:sonla", - - /* Kazakh in Arabic script */ - "m17n:kk:arabic", - - /* Yiddish */ - "m17n:yi:yivo", - - /* Canadian Aboriginal languages */ - "m17n:ath:phonetic", - "m17n:bla:phonetic", - "m17n:cr:western", - "m17n:iu:phonetic", - "m17n:nsk:phonetic", - "m17n:oj:phonetic", - - /* Non-trivial engines, like transliteration-based instead of - keymap-based. Confirmation needed that the engines below are - actually used by local language users. */ - - /* Tibetan */ - "m17n:bo:ewts", - "m17n:bo:tcrc", - "m17n:bo:wylie", - - /* Esperanto */ - "m17n:eo:h-f", - "m17n:eo:h", - "m17n:eo:plena", - "m17n:eo:q", - "m17n:eo:vi", - "m17n:eo:x", - - /* Amharic */ - "m17n:am:sera", - - /* Russian */ - "m17n:ru:translit", - - /* Classical Greek */ - "m17n:grc:mizuochi", - - /* Lao */ - "m17n:lo:lrt", - - /* Postfix modifier input methods */ - "m17n:da:post", - "m17n:sv:post", - NULL -}; #endif /* HAVE_IBUS */ static void populate_model (GtkListStore *store, @@ -447,10 +235,10 @@ IBusEngineDesc *engine = l->data; const gchar *engine_id = ibus_engine_desc_get_name (engine); - if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) - g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); - else + if (g_str_has_prefix (engine_id, "xkb:")) g_object_unref (engine); + else + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); } g_list_free (list); @@ -809,7 +597,7 @@ gtk_widget_set_sensitive (show_button, index >= 0); gtk_widget_set_sensitive (up_button, index > 0); gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); - gtk_widget_set_sensitive (settings_button, settings_sensitive); + gtk_widget_set_visible (settings_button, settings_sensitive); } static void @@ -1219,19 +1007,19 @@ static void update_shortcuts (GtkBuilder *builder) { - char *previous, *next; + char **previous, **next; GSettings *settings; - settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); - previous = g_settings_get_string (settings, "switch-input-source-backward"); - next = g_settings_get_string (settings, "switch-input-source"); + previous = g_settings_get_strv (settings, "switch-input-source-backward"); + next = g_settings_get_strv (settings, "switch-input-source"); - update_shortcut_label (WID ("prev-source-shortcut-label"), previous); - update_shortcut_label (WID ("next-source-shortcut-label"), next); + update_shortcut_label (WID ("prev-source-shortcut-label"), previous[0]); + update_shortcut_label (WID ("next-source-shortcut-label"), next[0]); - g_free (previous); - g_free (next); + g_strfreev (previous); + g_strfreev (next); } static gboolean @@ -1338,6 +1126,18 @@ "changed::" KEY_INPUT_SOURCES, G_CALLBACK (input_sources_changed), builder); + + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-true"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-false"), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + /* because we are in delay-apply mode */ + g_signal_connect_swapped (WID("per-window-radio-true"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); + g_signal_connect_swapped (WID("per-window-radio-false"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); } static void diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c --- gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c 2012-11-05 08:38:42.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.c 2015-02-22 15:27:38.000000000 +0000 @@ -92,7 +92,7 @@ gtk_widget_set_sensitive (button, TRUE); } -static void +void locale_settings_changed (GSettings *settings, const gchar *key, GtkBuilder *dialog) @@ -100,7 +100,7 @@ GtkWidget *label; gchar *region, *display_region; - region = g_settings_get_string (locale_settings, "region"); + region = cc_common_language_get_property ("FormatsLocale"); if (!region || !region[0]) { label = WID ("user_display_language"); region = g_strdup ((gchar*)g_object_get_data (G_OBJECT (label), "language")); @@ -226,6 +226,16 @@ } } +static gchar * +strip_quotes (const gchar *str) +{ + if ((g_str_has_prefix (str, "\"") && g_str_has_suffix (str, "\"")) + || (g_str_has_prefix (str, "'") && g_str_has_suffix (str, "'"))) + return g_strndup (str + 1, strlen (str) - 2); + else + return g_strdup (str); +} + static void on_localed_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, @@ -257,33 +267,43 @@ const gchar **strv; gsize len; gint i; - const gchar *lang, *messages, *time; + gchar *lang, *language, *messages, *time; gchar *name; GtkWidget *label; strv = g_variant_get_strv (v, &len); - lang = messages = time = NULL; + lang = language = messages = time = NULL; for (i = 0; strv[i]; i++) { if (g_str_has_prefix (strv[i], "LANG=")) { - lang = strv[i] + strlen ("LANG="); + lang = strip_quotes (strv[i] + strlen ("LANG=")); + } + else if (g_str_has_prefix (strv[i], "LANGUAGE=")) { + gchar *tmp = strip_quotes (strv[i] + strlen ("LANGUAGE=")); + gchar **tokens = g_strsplit (tmp, ":", 2); + language = g_strdup (tokens[0]); + g_free (tmp); + g_strfreev (tokens); } else if (g_str_has_prefix (strv[i], "LC_MESSAGES=")) { - messages = strv[i] + strlen ("LC_MESSAGES="); + messages = strip_quotes (strv[i] + strlen ("LC_MESSAGES=")); } else if (g_str_has_prefix (strv[i], "LC_TIME=")) { - time = strv[i] + strlen ("LC_TIME="); + time = strip_quotes (strv[i] + strlen ("LC_TIME=")); } } - if (!messages) { - messages = lang; + if (!language) { + if (messages) + language = g_strdup (messages); + else + language = g_strdup (lang); } if (!time) { - time = lang; + time = g_strdup (lang); } - if (messages) { - name = gdm_get_language_from_name (messages, NULL); + if (language) { + name = gdm_get_language_from_name (language, NULL); label = WID ("system_display_language"); gtk_label_set_text (GTK_LABEL (label), name); g_free (name); @@ -298,6 +318,10 @@ g_object_set_data_full (G_OBJECT (label), "region", g_strdup (time), g_free); } g_variant_unref (v); + g_free (lang); + g_free (language); + g_free (messages); + g_free (time); } label = WID ("system_input_source"); @@ -396,27 +420,44 @@ GtkWidget *label; GVariantBuilder *b; gchar *s; + gchar *command; + gchar *lang; + GError *error = NULL; + gint i; label = WID ("user_display_language"); language = g_object_get_data (G_OBJECT (label), "language"); label = WID ("user_format"); region = g_object_get_data (G_OBJECT (label), "region"); + /* Get locale that corresponds to the language */ + command = g_strconcat ("/usr/share/language-tools/language2locale ", language, NULL); + if (!g_spawn_command_line_sync (command, &lang, NULL, NULL, &error)) { + g_warning ("Couldn't get LANG locale: %s", error->message); + g_error_free (error); + g_free (command); + return; + } + g_free (command); + g_strchomp (lang); + if (strlen (lang) == 0) { + g_warning ("Couldn't get LANG locale -- Copying interrupted"); + return; + } + b = g_variant_builder_new (G_VARIANT_TYPE ("as")); - s = g_strconcat ("LANG=", language, NULL); + s = g_strconcat ("LANG=", lang, NULL); g_variant_builder_add (b, "s", s); + g_free (lang); g_free (s); - if (g_strcmp0 (language, region) != 0) { - s = g_strconcat ("LC_TIME=", region, NULL); - g_variant_builder_add (b, "s", s); - g_free (s); - s = g_strconcat ("LC_NUMERIC=", region, NULL); - g_variant_builder_add (b, "s", s); - g_free (s); - s = g_strconcat ("LC_MONETARY=", region, NULL); - g_variant_builder_add (b, "s", s); - g_free (s); - s = g_strconcat ("LC_MEASUREMENT=", region, NULL); + s = g_strconcat ("LANGUAGE=", language, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + const gchar *format_categories[] = { "LC_NUMERIC", "LC_TIME", + "LC_MONETARY", "LC_PAPER", "LC_IDENTIFICATION", "LC_NAME", + "LC_ADDRESS", "LC_TELEPHONE", "LC_MEASUREMENT", NULL }; + for (i = 0; format_categories[i] != NULL; i++) { + s = g_strconcat (format_categories[i], "=", region, NULL); g_variant_builder_add (b, "s", s); g_free (s); } @@ -525,7 +566,7 @@ g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, input_sources_settings); /* Display user settings */ - language = cc_common_language_get_current_language (); + language = cc_common_language_get_property ("Language"); system_update_language (dialog, language); g_free (language); diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h --- gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h 2011-09-01 10:01:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel-system.h 2015-02-22 15:27:38.000000000 +0000 @@ -27,5 +27,8 @@ void setup_system (GtkBuilder *builder); void system_update_language (GtkBuilder *builder, const gchar *language); +void locale_settings_changed (GSettings *settings, + const gchar *key, + GtkBuilder *dialog); #endif diff -Nru gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui --- gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui 2012-10-01 09:39:03.000000000 +0000 +++ gnome-control-center-3.6.3/panels/region/gnome-region-panel.ui 2015-02-22 15:27:39.000000000 +0000 @@ -154,7 +154,7 @@ - True + False False icons False @@ -862,111 +862,191 @@ - + True False - 0 - none - + True False - 12 + 0 + none - + True False - 6 - 6 - 6 - - - True - False - 0 - Switch to previous source - - - 0 - 0 - 1 - 1 - - + 12 - + True False - end - True - Ctrl+Alt+Space - - - - 1 - 0 - 1 - 1 - - - - - True - False - 0 - Switch to next source + 6 + 6 + 6 + + + True + False + 0 + Switch to previous source + + + 0 + 0 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Space + + + + 1 + 0 + 1 + 1 + + + + + True + False + 0 + Switch to next source + + + 0 + 1 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Shift+Space + + + + 1 + 1 + 1 + 1 + + + + + True + True + Shortcut Settings + end + + + 1 + 2 + 1 + 1 + + - - 0 - 1 - 1 - 1 - + + + + + True + False + Shortcuts + True + + + + + + + + False + False + 0 + + + + + True + False + 0 + none + + + True + False + 12 - + True False - end - True - Ctrl+Alt+Shift+Space - - - - 1 - 1 - 1 - 1 - - - - - True - True - Shortcut Settings - end + 6 + 6 + 6 + + + True + True + 0 + Use the same source for all windows + + + 0 + 0 + 1 + 1 + + + + + True + True + 0 + Allow different sources for each window + per-window-radio-false + + + 0 + 1 + 1 + 1 + + - - 1 - 2 - 1 - 1 - + + + True + False + Options + True + + + + + - - - - True - False - Shortcuts - True - - - - + + False + False + 1 + diff -Nru gnome-control-center-3.6.3/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/panels/screen/cc-screen-panel.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/screen/cc-screen-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -146,7 +146,10 @@ static const char * cc_screen_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/prefs-display"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; } static void @@ -347,9 +350,7 @@ 1, &value, -1); - /* set both battery and ac keys */ - g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); - g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + g_settings_set (self->priv->session_settings, "idle-delay", "u", value); set_idle_delay_from_dpms (self, value); } @@ -395,14 +396,13 @@ i = 0; /* try to make the UI match the AC setting */ - value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + g_settings_get (self->priv->session_settings, "idle-delay", "u", &value); do { gtk_tree_model_get (model, &iter, 1, &value_tmp, -1); - if (value == value_tmp || - (value_tmp > value_prev && value < value_tmp)) + if (value == value_tmp) { gtk_combo_box_set_active_iter (combo_box, &iter); return; @@ -507,7 +507,7 @@ /* bind the auto dim checkbox */ widget = WID ("screen_auto_reduce_checkbutton"); g_settings_bind (self->priv->gsd_settings, - "idle-dim-battery", + "idle-dim", widget, "active", G_SETTINGS_BIND_DEFAULT); @@ -543,9 +543,18 @@ "show-notifications", widget, "active", G_SETTINGS_BIND_DEFAULT); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_hide (widget); update_lock_screen_sensitivity (self); + /* bind the screen lock suspend checkbutton */ + widget = WID ("screen_lock_suspend_checkbutton"); + g_settings_bind (self->priv->lock_settings, + "ubuntu-lock-on-suspend", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + widget = WID ("screen_vbox"); gtk_widget_reparent (widget, (GtkWidget *) self); g_object_set (self, "valign", GTK_ALIGN_START, NULL); diff -Nru gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/screen/gnome-screen-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=screen diff -Nru gnome-control-center-3.6.3/panels/screen/screen.ui gnome-control-center-3.6.3/panels/screen/screen.ui --- gnome-control-center-3.6.3/panels/screen/screen.ui 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/screen/screen.ui 2015-02-22 15:27:39.000000000 +0000 @@ -83,6 +83,10 @@ 1 hour 3600 + + Never + 0 + @@ -294,6 +298,31 @@ + + True + False + 6 + + + Require my password when waking from suspend + False + True + True + + + False + False + 0 + + + + + False + False + 2 + + + False True @@ -335,7 +364,7 @@ True True - 2 + 3 @@ -360,7 +389,7 @@ True True - 3 + 4 diff -Nru gnome-control-center-3.6.3/panels/sound/cc-sound-panel.c gnome-control-center-3.6.3/panels/sound/cc-sound-panel.c --- gnome-control-center-3.6.3/panels/sound/cc-sound-panel.c 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/sound/cc-sound-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -70,7 +70,10 @@ static const char * cc_sound_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/media#sound"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/media#sound"; + else + return "help:gnome-help/media#sound"; } static void diff -Nru gnome-control-center-3.6.3/panels/sound/data/gnome-sound-applet.desktop.in gnome-control-center-3.6.3/panels/sound/data/gnome-sound-applet.desktop.in --- gnome-control-center-3.6.3/panels/sound/data/gnome-sound-applet.desktop.in 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/sound/data/gnome-sound-applet.desktop.in 2015-02-22 15:27:39.000000000 +0000 @@ -14,4 +14,4 @@ #X-GNOME-Autostart-Phase=Panel X-GNOME-Autostart-Notify=true AutostartCondition=GNOME3 if-session gnome-fallback -OnlyShowIn=GNOME;Unity; +OnlyShowIn=; diff -Nru gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/sound/data/gnome-sound-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=sound diff -Nru gnome-control-center-3.6.3/panels/sound/gvc-mixer-control.c gnome-control-center-3.6.3/panels/sound/gvc-mixer-control.c --- gnome-control-center-3.6.3/panels/sound/gvc-mixer-control.c 2012-10-22 12:50:11.000000000 +0000 +++ gnome-control-center-3.6.3/panels/sound/gvc-mixer-control.c 2015-02-22 15:27:39.000000000 +0000 @@ -2138,7 +2138,7 @@ else { for (i = 0; i < info->n_ports; i++) { if (g_strcmp0 (card_port->port, info->ports[i]->name) == 0) { - if (card_port->available != info->ports[i]->available) { + if ((card_port->available == PA_PORT_AVAILABLE_NO) != (info->ports[i]->available == PA_PORT_AVAILABLE_NO)) { card_port->available = info->ports[i]->available; g_debug ("sync port availability on card %i, card port name '%s', new available value %i", gvc_mixer_card_get_index (card), diff -Nru gnome-control-center-3.6.3/panels/sound/gvc-sound-theme-chooser.c gnome-control-center-3.6.3/panels/sound/gvc-sound-theme-chooser.c --- gnome-control-center-3.6.3/panels/sound/gvc-sound-theme-chooser.c 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/sound/gvc-sound-theme-chooser.c 2015-02-22 15:27:39.000000000 +0000 @@ -67,7 +67,7 @@ #define DEFAULT_ALERT_ID "__default" #define CUSTOM_THEME_NAME "__custom" #define NO_SOUNDS_THEME_NAME "__no_sounds" -#define DEFAULT_THEME "freedesktop" +#define DEFAULT_THEME "ubuntu" enum { THEME_DISPLAY_COL, diff -Nru gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c --- gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/universal-access/cc-ua-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -40,7 +40,7 @@ #define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" #define KEY_GTK_THEME "gtk-theme" #define KEY_ICON_THEME "icon-theme" - +#define KEY_WM_THEME "theme" CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel) @@ -159,7 +159,10 @@ static const char * cc_ua_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/a11y"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/a11y"; + else + return "help:gnome-help/a11y"; } static void @@ -379,19 +382,24 @@ gpointer user_data) { gboolean hc; - GSettings *settings = user_data; + CcUaPanel *self = user_data; + CcUaPanelPrivate *priv = self->priv; GVariant *ret = NULL; hc = g_value_get_boolean (value); if (hc) { ret = g_variant_new_string (HIGH_CONTRAST_THEME); - g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); + g_settings_set_string (priv->interface_settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); + + g_settings_set_string (priv->wm_settings, KEY_WM_THEME, HIGH_CONTRAST_THEME); } else { - g_settings_reset (settings, KEY_GTK_THEME); - g_settings_reset (settings, KEY_ICON_THEME); + g_settings_reset (priv->interface_settings, KEY_GTK_THEME); + g_settings_reset (priv->interface_settings, KEY_ICON_THEME); + + g_settings_reset (priv->wm_settings, KEY_WM_THEME); } return ret; @@ -407,7 +415,7 @@ "active", G_SETTINGS_BIND_DEFAULT, get_contrast_mapping, set_contrast_mapping, - priv->interface_settings, + self, NULL); g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR, WID (priv->builder, "seeing_large_text_switch"), @@ -421,13 +429,21 @@ WID (priv->builder, "seeing_toggle_keys_switch"), "active", G_SETTINGS_BIND_DEFAULT); - priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity")) + { + priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "org.gnome.Shell", G_BUS_NAME_WATCHER_FLAGS_NONE, (GBusNameAppearedCallback) shell_appeared_cb, (GBusNameVanishedCallback) shell_vanished_cb, self, NULL); + } else + { + gtk_widget_hide (WID (priv->builder, "zoom_label_box")); + gtk_widget_hide (WID (priv->builder, "zoom_value_box")); + } + g_signal_connect (WID (priv->builder, "seeing_zoom_preferences_button"), "clicked", G_CALLBACK (zoom_options_launch_cb), self); diff -Nru gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in 2012-05-24 14:20:10.000000000 +0000 +++ gnome-control-center-3.6.3/panels/universal-access/gnome-universal-access-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=Universal Access diff -Nru gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=System;Settings;X-GNOME-Settings-Panel;X-GNOME-SystemSettings -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=user-accounts diff -Nru gnome-control-center-3.6.3/panels/user-accounts/run-passwd.c gnome-control-center-3.6.3/panels/user-accounts/run-passwd.c --- gnome-control-center-3.6.3/panels/user-accounts/run-passwd.c 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/run-passwd.c 2015-02-22 15:27:38.000000000 +0000 @@ -406,7 +406,7 @@ if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) { - if (strstr (str->str, "assword: ") != NULL) { + if (strstr (str->str, "assword: ") != NULL && strstr (str->str, "incorrect") == NULL) { /* Authentication successful */ passwd_handler->backend_state = PASSWD_STATE_NEW; diff -Nru gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c --- gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/um-password-dialog.c 2015-02-22 15:27:38.000000000 +0000 @@ -52,6 +52,7 @@ GtkWidget *ok_button; UmUser *user; + gboolean using_ecryptfs; GtkWidget *old_password_label; GtkWidget *old_password_entry; @@ -471,6 +472,38 @@ } } +int _is_gdm_running = -1; +gboolean +is_gdm_running (void) +{ + if (_is_gdm_running == -1) { + GDBusProxy *proxy; + gchar *owner_name; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + "org.gnome.DisplayManager", + "/org/gnome/DisplayManager/Manager", + "org.gnome.DisplayManager.Manager", + NULL, NULL); + + if (proxy == NULL) + return FALSE; + + owner_name = g_dbus_proxy_get_name_owner (proxy); + + g_object_unref (proxy); + g_free (owner_name); + + _is_gdm_running = (owner_name != NULL) ? 1 : 0; + } + + return _is_gdm_running; +} + UmPasswordDialog * um_password_dialog_new (void) { @@ -523,9 +556,14 @@ widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label"); old_label = gtk_label_get_label (GTK_LABEL (widget)); - label = g_strdup_printf ("%s", - "help:gnome-help/user-goodpassword", - old_label); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + label = g_strdup_printf ("%s", + "help:ubuntu-help/user-goodpassword", + old_label); + else + label = g_strdup_printf ("%s", + "help:gnome-help/user-goodpassword", + old_label); gtk_label_set_markup (GTK_LABEL (widget), label); g_free (label); @@ -586,6 +624,13 @@ G_CALLBACK (entry_size_changed), widget); um->normal_hint_label = widget; + if (!is_gdm_running ()) { + widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-hint-label"); + gtk_widget_hide (widget); + gtk_widget_hide (um->normal_hint_entry); + gtk_widget_hide (um->normal_hint_label); + } + um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator"); um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); @@ -620,6 +665,12 @@ gtk_tree_model_get (model, iter, 1, &mode, -1); + if (mode == 1 && !is_gdm_running ()) + return FALSE; + + if (mode == 2 && um->using_ecryptfs) + return FALSE; + if (mode == 3 && locked) return FALSE; @@ -646,6 +697,8 @@ if (user) { um->user = g_object_ref (user); + um->using_ecryptfs = is_using_ecryptfs (um_user_get_user_name (user)); + pixbuf = um_user_render_icon (user, FALSE, 48); gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf); g_object_unref (pixbuf); diff -Nru gnome-control-center-3.6.3/panels/user-accounts/um-user.c gnome-control-center-3.6.3/panels/user-accounts/um-user.c --- gnome-control-center-3.6.3/panels/user-accounts/um-user.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/um-user.c 2015-02-22 15:27:39.000000000 +0000 @@ -730,7 +730,7 @@ GVariant *result; GError *error = NULL; - result = g_dbus_proxy_call_sync (user->proxy, "SetIconFile", g_variant_new ("(s)", icon_file), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + result = g_dbus_proxy_call_sync (user->proxy, "SetIconFile", g_variant_new ("(s)", icon_file ? icon_file : ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (!result) { g_warning ("SetIconFile call failed: %s", error->message); g_error_free (error); diff -Nru gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c --- gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/um-user-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -629,7 +629,10 @@ /* Autologin: show when local account */ widget = get_widget (d, "autologin-switch"); label = get_widget (d, "autologin-label"); - show = um_user_is_local_account (user); + /* Don't show autologin option if ecryptfs is in use, because it won't + work if user turns it on. */ + show = um_user_is_local_account (user) && + !is_using_ecryptfs (um_user_get_user_name (user)); gtk_widget_set_visible (widget, show); gtk_widget_set_visible (label, show); } @@ -1372,7 +1375,10 @@ static const char * um_user_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/user-accounts"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/user-accounts"; + else + return "help:gnome-help/user-accounts"; } static void diff -Nru gnome-control-center-3.6.3/panels/user-accounts/um-utils.c gnome-control-center-3.6.3/panels/user-accounts/um-utils.c --- gnome-control-center-3.6.3/panels/user-accounts/um-utils.c 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/um-utils.c 2015-02-22 15:27:38.000000000 +0000 @@ -746,3 +746,27 @@ g_string_free (item3, TRUE); g_string_free (item4, TRUE); } + +gboolean +is_using_ecryptfs (const gchar *name) +{ + gboolean using_ecryptfs = FALSE; + int status; + gchar *prog; + gchar *cmd; + + prog = g_find_program_in_path ("ecryptfs-verify"); + if (prog != NULL) { + gchar *cmd = g_strdup_printf("'%s' -h -u '%s'", prog, name); + + if (g_spawn_command_line_sync (cmd, NULL, NULL, &status, NULL)) { + if (status == 0) + using_ecryptfs = TRUE; + } + + g_free (prog); + g_free (cmd); + } + + return using_ecryptfs; +} diff -Nru gnome-control-center-3.6.3/panels/user-accounts/um-utils.h gnome-control-center-3.6.3/panels/user-accounts/um-utils.h --- gnome-control-center-3.6.3/panels/user-accounts/um-utils.h 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/user-accounts/um-utils.h 2015-02-22 15:27:38.000000000 +0000 @@ -65,6 +65,8 @@ void generate_username_choices (const gchar *name, GtkListStore *store); +gboolean is_using_ecryptfs (const gchar *name); + G_END_DECLS #endif diff -Nru gnome-control-center-3.6.3/panels/wacom/cc-wacom-panel.c gnome-control-center-3.6.3/panels/wacom/cc-wacom-panel.c --- gnome-control-center-3.6.3/panels/wacom/cc-wacom-panel.c 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/wacom/cc-wacom-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -123,7 +123,10 @@ static const char * cc_wacom_panel_get_help_uri (CcPanel *panel) { - return "help:gnome-help/wacom"; + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/wacom"; + else + return "help:gnome-help/wacom"; } static void diff -Nru gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in --- gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/panels/wacom/gnome-wacom-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=wacom diff -Nru gnome-control-center-3.6.3/.pc/0001-online-accounts-use-the-async-function-to-get-all-th.patch/panels/online-accounts/cc-online-accounts-panel.c gnome-control-center-3.6.3/.pc/0001-online-accounts-use-the-async-function-to-get-all-th.patch/panels/online-accounts/cc-online-accounts-panel.c --- gnome-control-center-3.6.3/.pc/0001-online-accounts-use-the-async-function-to-get-all-th.patch/panels/online-accounts/cc-online-accounts-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/0001-online-accounts-use-the-async-function-to-get-all-th.patch/panels/online-accounts/cc-online-accounts-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,769 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2011, 2012 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include +#include + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#include +#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE +#include + +#include "cc-online-accounts-panel.h" + +#include "cc-online-accounts-add-account-dialog.h" +#include "cc-online-accounts-model.h" + +typedef struct _GoaPanelClass GoaPanelClass; + +struct _GoaPanel +{ + CcPanel parent_instance; + + GtkBuilder *builder; + + GoaClient *client; + + GoaPanelAccountsModel *accounts_model; + + GtkWidget *toolbar; + GtkWidget *toolbar_add_button; + GtkWidget *toolbar_remove_button; + GtkWidget *accounts_treeview; + GtkWidget *accounts_vbox; +}; + +struct _GoaPanelClass +{ + CcPanelClass parent_class; +}; + +static void on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data); +static void on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data); + +static void on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data); + +static void on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data); +static void on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data); + +static void on_add_button_clicked (GtkButton *button, + gpointer user_data); + +static void on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static gboolean select_account_by_id (GoaPanel *panel, + const gchar *account_id); + +CC_PANEL_REGISTER (GoaPanel, goa_panel); + +enum { + PROP_0, + PROP_ARGV +}; + +static void +goa_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + case PROP_ARGV: + { + gchar **args; + + args = g_value_get_boxed (value); + + if (args != NULL && *args != '\0') + select_account_by_id (GOA_PANEL (object), args[0]); + return; + } + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +goa_panel_finalize (GObject *object) +{ + GoaPanel *panel = GOA_PANEL (object); + + if (panel->accounts_model != NULL) + g_clear_object (&panel->accounts_model); + + if (panel->client != NULL) + g_object_unref (panel->client); + g_object_unref (panel->builder); + + G_OBJECT_CLASS (goa_panel_parent_class)->finalize (object); +} + +static void +goa_panel_init (GoaPanel *panel) +{ + GtkWidget *button; + GtkWidget *w; + GError *error; + GtkStyleContext *context; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + + panel->builder = gtk_builder_new (); + error = NULL; + if (gtk_builder_add_from_file (panel->builder, + GNOMECC_UI_DIR "/online-accounts.ui", + &error) == 0) + { + goa_warning ("Error loading UI file: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + g_error_free (error); + goto out; + } + + panel->toolbar = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbar")); + panel->toolbar_add_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-add")); + g_signal_connect (panel->toolbar_add_button, + "clicked", + G_CALLBACK (on_toolbar_add_button_clicked), + panel); + panel->toolbar_remove_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-remove")); + g_signal_connect (panel->toolbar_remove_button, + "clicked", + G_CALLBACK (on_toolbar_remove_button_clicked), + panel); + + context = gtk_widget_get_style_context (GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-scrolledwindow"))); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + context = gtk_widget_get_style_context (panel->toolbar); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + panel->accounts_treeview = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-treeview")); + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + "changed", + G_CALLBACK (on_tree_view_selection_changed), + panel); + + button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-button-add")); + g_signal_connect (button, + "clicked", + G_CALLBACK (on_add_button_clicked), + panel); + + panel->accounts_vbox = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-vbox")); + + /* TODO: probably want to avoid _sync() ... */ + error = NULL; + panel->client = goa_client_new_sync (NULL /* GCancellable */, &error); + if (panel->client == NULL) + { + goa_warning ("Error getting a GoaClient: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_set_sensitive (w, FALSE); + g_error_free (error); + goto out; + } + g_signal_connect (panel->client, + "account-changed", + G_CALLBACK (on_account_changed), + panel); + + panel->accounts_model = goa_panel_accounts_model_new (panel->client); + gtk_tree_view_set_model (GTK_TREE_VIEW (panel->accounts_treeview), GTK_TREE_MODEL (panel->accounts_model)); + g_signal_connect (panel->accounts_model, "row-deleted", G_CALLBACK (on_model_row_deleted), panel); + g_signal_connect (panel->accounts_model, "row-inserted", G_CALLBACK (on_model_row_inserted), panel); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (panel->accounts_treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "gicon", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "ellipsize", PANGO_ELLIPSIZE_END, + "ellipsize-set", TRUE, + "width-chars", 30, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "markup", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_MARKUP, + NULL); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_end (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "icon-name", "dialog-error-symbolic", + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "visible", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ATTENTION_NEEDED, + NULL); + + /* Select the first row, if any */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (panel->accounts_model), + &iter)) + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + &iter); + + out: + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_reparent (w, GTK_WIDGET (panel)); + gtk_widget_show_all (w); +} + +static const char * +goa_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/accounts"; +} + +static void +goa_panel_class_init (GoaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = goa_panel_get_help_uri; + + object_class->set_property = goa_panel_set_property; + object_class->finalize = goa_panel_finalize; + + g_object_class_override_property (object_class, PROP_ARGV, "argv"); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +goa_panel_register (GIOModule *module) +{ + goa_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + GOA_TYPE_PANEL, + "online-accounts", + 0); +} + +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + goa_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +show_page (GoaPanel *panel, + gint page_num) +{ + GtkNotebook *notebook; + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->builder, "accounts-notebook")); + gtk_notebook_set_current_page (notebook, page_num); +} + +static void +show_page_nothing_selected (GoaPanel *panel) +{ + GtkWidget *box; + GtkWidget *label; + + show_page (panel, 0); + + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, FALSE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_show (label); +} + +static void +on_info_bar_response (GtkInfoBar *info_bar, + gint response_id, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaProvider *provider; + const gchar *provider_type; + GoaAccount *account; + GoaObject *object; + GtkWindow *parent; + GError *error; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); + + error = NULL; + if (!goa_provider_refresh_account (provider, + panel->client, + object, + parent, + &error)) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error logging into the account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + g_object_unref (provider); + g_object_unref (object); + } +} + +static void +show_page_account (GoaPanel *panel, + GoaObject *object) +{ + GList *children; + GList *l; + GtkWidget *box; + GtkWidget *grid; + GtkWidget *left_grid; + GtkWidget *right_grid; + GtkWidget *bar; + GtkWidget *label; + GoaProvider *provider; + GoaAccount *account; + const gchar *provider_type; + + provider = NULL; + + show_page (panel, 1); + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, TRUE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_hide (label); + + /* Out with the old */ + children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_vbox)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (panel->accounts_vbox), GTK_WIDGET (l->data)); + g_list_free (children); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + /* And in with the new */ + if (goa_account_get_attention_needed (account)) + { + bar = gtk_info_bar_new (); + label = gtk_label_new (_("Expired credentials. Please log in again.")); + gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label); + if (provider != NULL) + gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("_Log In"), GTK_RESPONSE_OK); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), bar, FALSE, TRUE, 0); + g_signal_connect (bar, "response", G_CALLBACK (on_info_bar_response), panel); + } + + left_grid = gtk_grid_new (); + gtk_widget_set_halign (left_grid, GTK_ALIGN_END); + gtk_widget_set_hexpand (left_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (left_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (left_grid), 0); + + right_grid = gtk_grid_new (); + gtk_widget_set_hexpand (right_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (right_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (right_grid), 0); + + if (provider != NULL) + { + goa_provider_show_account (provider, + panel->client, + object, + GTK_BOX (panel->accounts_vbox), + GTK_GRID (left_grid), + GTK_GRID (right_grid)); + } + + grid = gtk_grid_new (); + gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL); + gtk_grid_set_column_spacing (GTK_GRID (grid), 12); + gtk_container_add (GTK_CONTAINER (grid), left_grid); + gtk_container_add (GTK_CONTAINER (grid), right_grid); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), grid, FALSE, TRUE, 0); + + gtk_widget_show_all (panel->accounts_vbox); + + if (provider != NULL) + g_object_unref (provider); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +select_account_by_id (GoaPanel *panel, + const gchar *account_id) +{ + GoaObject *goa_object = NULL; + GtkTreeIter iter; + gboolean iter_set = FALSE; + + goa_object = goa_client_lookup_by_id (panel->client, account_id); + if (goa_object != NULL) + { + iter_set = goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, + goa_object, + &iter); + g_object_unref (goa_object); + } + + if (iter_set) + { + GtkTreeView *tree_view; + GtkTreeSelection *selection; + + tree_view = GTK_TREE_VIEW (panel->accounts_treeview); + selection = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_select_iter (selection, &iter); + } + + return iter_set; +} + +static void +on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GoaObject *object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + show_page_account (panel, object); + g_object_unref (object); + } + else + { + show_page_nothing_selected (panel); + } +} + +static void +on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *selected_object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &selected_object, + -1); + if (selected_object == object) + show_page_account (panel, selected_object); + g_object_unref (selected_object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_model_row_changed (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GtkTreeSelection *selection = GTK_TREE_SELECTION (user_data); + + gtk_tree_selection_select_iter (selection, iter); + g_signal_handlers_disconnect_by_func (tree_model, G_CALLBACK (on_model_row_changed), user_data); +} + +static void +on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + GtkTreeSelection *selection; + + if (!gtk_tree_model_get_iter (tree_model, &iter, path)) + { + if (!gtk_tree_path_prev (path)) + return; + } + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + gtk_tree_selection_select_path (selection, path); +} + +static void +on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + if (gtk_tree_selection_get_selected (selection, NULL, NULL)) + return; + + /* An empty row has been inserted and is going to be filled in, so + * we expect selection to stay valid. + */ + g_signal_connect (tree_model, "row-changed", G_CALLBACK (on_model_row_changed), selection); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +add_account (GoaPanel *panel) +{ + GtkWindow *parent; + GtkWidget *dialog; + gint response; + GList *providers; + GList *l; + GoaObject *object; + GError *error; + + providers = NULL; + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); + + dialog = goa_panel_add_account_dialog_new (panel->client); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + providers = goa_provider_get_all (); + for (l = providers; l != NULL; l = l->next) + { + GoaProvider *provider; + + provider = GOA_PROVIDER (l->data); + goa_panel_add_account_dialog_add_provider (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), provider); + } + + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + if (response != GTK_RESPONSE_OK) + { + gtk_widget_destroy (dialog); + goto out; + } + + error = NULL; + object = goa_panel_add_account_dialog_get_account (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), &error); + gtk_widget_destroy (dialog); + + /* We might have an object even when error is set. + * eg., if we failed to store the credentials in the keyring. + */ + + if (object != NULL) + { + GtkTreeIter iter; + /* navigate to newly created object */ + if (goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, + object, + &iter)) + { + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + &iter); + } + g_object_unref (object); + } + + if (error != NULL) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error creating account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + + out: + g_list_foreach (providers, (GFunc) g_object_unref, NULL); + g_list_free (providers); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} + +static void +remove_account_cb (GoaAccount *account, + GAsyncResult *res, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GError *error; + + error = NULL; + if (!goa_account_call_remove_finish (account, res, &error)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error removing account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } + g_object_unref (panel); +} + +static void +on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *object; + GtkWidget *dialog; + gint response; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + _("Are you sure you want to remove the account?")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("This will not remove the account on the server.")); + gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Remove"), GTK_RESPONSE_OK); + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (response == GTK_RESPONSE_OK) + { + goa_account_call_remove (goa_object_peek_account (object), + NULL, /* GCancellable */ + (GAsyncReadyCallback) remove_account_cb, + g_object_ref (panel)); + } + g_object_unref (object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_add_button_clicked (GtkButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} diff -Nru gnome-control-center-3.6.3/.pc/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch/panels/network/rfkill-glib.c gnome-control-center-3.6.3/.pc/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch/panels/network/rfkill-glib.c --- gnome-control-center-3.6.3/.pc/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch/panels/network/rfkill-glib.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch/panels/network/rfkill-glib.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,299 @@ +/* + * + * gnome-bluetooth - Bluetooth integration for GNOME + * + * Copyright (C) 2012 Bastien Nocera + * + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "rfkill-glib.h" + +enum { + CHANGED, + LAST_SIGNAL +}; + +static int signals[LAST_SIGNAL] = { 0 }; + +#define CC_RFKILL_GLIB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + CC_RFKILL_TYPE_GLIB, CcRfkillGlibPrivate)) + +struct CcRfkillGlibPrivate { + int fd; + GIOChannel *channel; + guint watch_id; +}; + +G_DEFINE_TYPE(CcRfkillGlib, cc_rfkill_glib, G_TYPE_OBJECT) + +int +cc_rfkill_glib_send_event (CcRfkillGlib *rfkill, struct rfkill_event *event) +{ + g_return_val_if_fail (RFKILL_IS_GLIB (rfkill), -1); + g_return_val_if_fail (rfkill->priv->fd > 0, -1); + + return write (rfkill->priv->fd, event, sizeof(struct rfkill_event)); +} + +static const char * +type_to_string (unsigned int type) +{ + switch (type) { + case RFKILL_TYPE_ALL: + return "ALL"; + case RFKILL_TYPE_WLAN: + return "WLAN"; + case RFKILL_TYPE_BLUETOOTH: + return "RFKILL"; + case RFKILL_TYPE_UWB: + return "UWB"; + case RFKILL_TYPE_WIMAX: + return "WIMAX"; + case RFKILL_TYPE_WWAN: + return "WWAN"; + default: + g_assert_not_reached (); + } +} + +static const char * +op_to_string (unsigned int op) +{ + switch (op) { + case RFKILL_OP_ADD: + return "ADD"; + case RFKILL_OP_DEL: + return "DEL"; + case RFKILL_OP_CHANGE: + return "CHANGE"; + case RFKILL_OP_CHANGE_ALL: + return "CHANGE_ALL"; + default: + g_assert_not_reached (); + } +} + +static void +print_event (struct rfkill_event *event) +{ + g_debug ("RFKILL event: idx %u type %u (%s) op %u (%s) soft %u hard %u", + event->idx, + event->type, type_to_string (event->type), + event->op, op_to_string (event->op), + event->soft, event->hard); +} + +static void +emit_changed_signal_and_free (CcRfkillGlib *rfkill, + GList *events) +{ + if (events == NULL) + return; + + g_signal_emit (G_OBJECT (rfkill), + signals[CHANGED], + 0, events); + g_list_free_full (events, g_free); +} + +static gboolean +event_cb (GIOChannel *source, + GIOCondition condition, + CcRfkillGlib *rfkill) +{ + GList *events; + + events = NULL; + + if (condition & G_IO_IN) { + GIOStatus status; + struct rfkill_event event; + gsize read; + + status = g_io_channel_read_chars (source, + (char *) &event, + sizeof(event), + &read, + NULL); + + while (status == G_IO_STATUS_NORMAL && read == sizeof(event)) { + struct rfkill_event *event_ptr; + + print_event (&event); + + event_ptr = g_memdup (&event, sizeof(event)); + events = g_list_prepend (events, event_ptr); + + status = g_io_channel_read_chars (source, + (char *) &event, + sizeof(event), + &read, + NULL); + } + events = g_list_reverse (events); + } else { + g_debug ("something else happened"); + return FALSE; + } + + emit_changed_signal_and_free (rfkill, events); + + return TRUE; +} + +static void +cc_rfkill_glib_init (CcRfkillGlib *rfkill) +{ + CcRfkillGlibPrivate *priv; + + priv = CC_RFKILL_GLIB_GET_PRIVATE (rfkill); + rfkill->priv = priv; + rfkill->priv->fd = -1; +} + +int +cc_rfkill_glib_open (CcRfkillGlib *rfkill) +{ + CcRfkillGlibPrivate *priv; + int fd; + int ret; + GList *events; + + g_return_val_if_fail (RFKILL_IS_GLIB (rfkill), -1); + g_return_val_if_fail (rfkill->priv->fd == -1, -1); + + priv = rfkill->priv; + + fd = open("/dev/rfkill", O_RDWR); + if (fd < 0) { + if (errno == EACCES) + g_warning ("Could not open RFKILL control device, please verify your installation"); + return fd; + } + + ret = fcntl(fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + g_debug ("Can't set RFKILL control device to non-blocking"); + close(fd); + return ret; + } + + events = NULL; + + while (1) { + struct rfkill_event event; + struct rfkill_event *event_ptr; + ssize_t len; + + len = read(fd, &event, sizeof(event)); + if (len < 0) { + if (errno == EAGAIN) + break; + g_debug ("Reading of RFKILL events failed"); + break; + } + + if (len != RFKILL_EVENT_SIZE_V1) { + g_warning ("Wrong size of RFKILL event\n"); + continue; + } + + if (event.op != RFKILL_OP_ADD) + continue; + + g_debug ("Read killswitch of type '%s' (idx=%d): soft %d hard %d", + type_to_string (event.type), + event.idx, event.soft, event.hard); + + event_ptr = g_memdup (&event, sizeof(event)); + events = g_list_prepend (events, event_ptr); + } + + /* Setup monitoring */ + priv->fd = fd; + priv->channel = g_io_channel_unix_new (priv->fd); + priv->watch_id = g_io_add_watch (priv->channel, + G_IO_IN | G_IO_HUP | G_IO_ERR, + (GIOFunc) event_cb, + rfkill); + + events = g_list_reverse (events); + emit_changed_signal_and_free (rfkill, events); + + return fd; +} + +static void +cc_rfkill_glib_finalize (GObject *object) +{ + CcRfkillGlib *rfkill; + CcRfkillGlibPrivate *priv; + + rfkill = CC_RFKILL_GLIB (object); + priv = rfkill->priv; + + /* cleanup monitoring */ + if (priv->watch_id > 0) { + g_source_remove (priv->watch_id); + priv->watch_id = 0; + g_io_channel_shutdown (priv->channel, FALSE, NULL); + g_io_channel_unref (priv->channel); + } + close(priv->fd); + priv->fd = -1; + + G_OBJECT_CLASS(cc_rfkill_glib_parent_class)->finalize(object); +} + +static void +cc_rfkill_glib_class_init(CcRfkillGlibClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + g_type_class_add_private(klass, sizeof(CcRfkillGlibPrivate)); + object_class->finalize = cc_rfkill_glib_finalize; + + signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CcRfkillGlibClass, changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + +} + +CcRfkillGlib * +cc_rfkill_glib_new (void) +{ + return CC_RFKILL_GLIB (g_object_new (CC_RFKILL_TYPE_GLIB, NULL)); +} diff -Nru gnome-control-center-3.6.3/.pc/05_run_update_manager.patch/panels/info/cc-info-panel.c gnome-control-center-3.6.3/.pc/05_run_update_manager.patch/panels/info/cc-info-panel.c --- gnome-control-center-3.6.3/.pc/05_run_update_manager.patch/panels/info/cc-info-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/05_run_update_manager.patch/panels/info/cc-info-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2034 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "cc-info-panel.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "hostname-helper.h" +#include "gsd-disk-space-helper.h" + +/* Autorun options */ +#define PREF_MEDIA_AUTORUN_NEVER "autorun-never" +#define PREF_MEDIA_AUTORUN_X_CONTENT_START_APP "autorun-x-content-start-app" +#define PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE "autorun-x-content-ignore" +#define PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER "autorun-x-content-open-folder" + +#define CUSTOM_ITEM_ASK "cc-item-ask" +#define CUSTOM_ITEM_DO_NOTHING "cc-item-do-nothing" +#define CUSTOM_ITEM_OPEN_FOLDER "cc-item-open-folder" + +#define MEDIA_HANDLING_SCHEMA "org.gnome.desktop.media-handling" + +/* Session */ +#define GNOME_SESSION_MANAGER_SCHEMA "org.gnome.desktop.session" +#define KEY_SESSION_NAME "session-name" + +#define WID(w) (GtkWidget *) gtk_builder_get_object (self->priv->builder, w) + +CC_PANEL_REGISTER (CcInfoPanel, cc_info_panel) + +#define INFO_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_INFO_PANEL, CcInfoPanelPrivate)) + +typedef struct { + /* Will be one of the other two below, or "Unknown" */ + const char *hardware_string; + + char *xorg_vesa_hardware; + char *glx_renderer; +} GraphicsData; + +typedef enum { + PK_NOT_AVAILABLE, + UPDATES_AVAILABLE, + UPDATES_NOT_AVAILABLE, + CHECKING_UPDATES +} UpdatesState; + +typedef struct +{ + const char *content_type; + const char *label; + /* A pattern used to filter supported mime types + when changing preferred applications. NULL + means no other types should be changed */ + const char *extra_type_filter; +} DefaultAppData; + +struct _CcInfoPanelPrivate +{ + GtkBuilder *builder; + char *gnome_version; + char *gnome_distributor; + char *gnome_date; + UpdatesState updates_state; + gboolean is_fallback; + + /* Free space */ + GList *primary_mounts; + guint64 total_bytes; + GCancellable *cancellable; + + /* Media */ + GSettings *media_settings; + GtkWidget *other_application_combo; + + GDBusConnection *session_bus; + GDBusProxy *pk_proxy; + GDBusProxy *pk_transaction_proxy; + GDBusProxy *hostnamed_proxy; + GSettings *session_settings; + + GraphicsData *graphics_data; +}; + +static void get_primary_disc_info_start (CcInfoPanel *self); +static void refresh_update_button (CcInfoPanel *self); + +typedef struct +{ + char *major; + char *minor; + char *micro; + char *distributor; + char *date; + char **current; +} VersionData; + +static void +version_start_element_handler (GMarkupParseContext *ctx, + const char *element_name, + const char **attr_names, + const char **attr_values, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (g_str_equal (element_name, "platform")) + data->current = &data->major; + else if (g_str_equal (element_name, "minor")) + data->current = &data->minor; + else if (g_str_equal (element_name, "micro")) + data->current = &data->micro; + else if (g_str_equal (element_name, "distributor")) + data->current = &data->distributor; + else if (g_str_equal (element_name, "date")) + data->current = &data->date; + else + data->current = NULL; +} + +static void +version_end_element_handler (GMarkupParseContext *ctx, + const char *element_name, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + data->current = NULL; +} + +static void +version_text_handler (GMarkupParseContext *ctx, + const char *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (data->current != NULL) + *data->current = g_strstrip (g_strdup (text)); +} + +static gboolean +load_gnome_version (char **version, + char **distributor, + char **date) +{ + GMarkupParser version_parser = { + version_start_element_handler, + version_end_element_handler, + version_text_handler, + NULL, + NULL, + }; + GError *error; + GMarkupParseContext *ctx; + char *contents; + gsize length; + VersionData *data; + gboolean ret; + + ret = FALSE; + + error = NULL; + if (!g_file_get_contents (DATADIR "/gnome/gnome-version.xml", + &contents, + &length, + &error)) + return FALSE; + + data = g_new0 (VersionData, 1); + ctx = g_markup_parse_context_new (&version_parser, 0, data, NULL); + + if (!g_markup_parse_context_parse (ctx, contents, length, &error)) + { + g_warning ("Invalid version file: '%s'", error->message); + } + else + { + if (version != NULL) + *version = g_strdup_printf ("%s.%s.%s", data->major, data->minor, data->micro); + if (distributor != NULL) + *distributor = g_strdup (data->distributor); + if (date != NULL) + *date = g_strdup (data->date); + + ret = TRUE; + } + + g_markup_parse_context_free (ctx); + g_free (data->major); + g_free (data->minor); + g_free (data->micro); + g_free (data->distributor); + g_free (data->date); + g_free (data); + g_free (contents); + + return ret; +}; + +typedef struct +{ + char *regex; + char *replacement; +} ReplaceStrings; + +static char * +prettify_info (const char *info) +{ + char *pretty; + int i; + static const ReplaceStrings rs[] = { + { "Mesa DRI ", ""}, + { "Intel[(]R[)]", "Intel\302\256"}, + { "Core[(]TM[)]", "Core\342\204\242"}, + { "Atom[(]TM[)]", "Atom\342\204\242"}, + { "Graphics Controller", "Graphics"}, + }; + + pretty = g_markup_escape_text (info, -1); + + for (i = 0; i < G_N_ELEMENTS (rs); i++) + { + GError *error; + GRegex *re; + char *new; + + error = NULL; + + re = g_regex_new (rs[i].regex, 0, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + continue; + } + + new = g_regex_replace_literal (re, + pretty, + -1, + 0, + rs[i].replacement, + 0, + &error); + + g_regex_unref (re); + + if (error != NULL) + { + g_warning ("Error replacing %s: %s", rs[i].regex, error->message); + g_error_free (error); + continue; + } + + g_free (pretty); + pretty = new; + } + + return pretty; +} + +static void +graphics_data_free (GraphicsData *gdata) +{ + g_free (gdata->xorg_vesa_hardware); + g_free (gdata->glx_renderer); + g_slice_free (GraphicsData, gdata); +} + +static char * +get_graphics_data_glx_renderer (void) +{ + GError *error; + GRegex *re; + GMatchInfo *match_info; + char *output; + char *result; + GString *info; + + info = g_string_new (NULL); + + error = NULL; + g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error); + if (error != NULL) + { + g_warning ("Unable to get graphics info: %s", error->message); + g_error_free (error); + return NULL; + } + + re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + goto out; + } + + g_regex_match (re, output, 0, &match_info); + while (g_match_info_matches (match_info)) + { + char *device; + + device = g_match_info_fetch (match_info, 1); + g_string_append_printf (info, "%s ", device); + g_free (device); + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + g_regex_unref (re); + + out: + g_free (output); + result = prettify_info (info->str); + g_string_free (info, TRUE); + + return result; +} + +static char * +get_graphics_data_xorg_vesa_hardware (void) +{ + char *display_num; + char *log_path; + char *log_contents; + gsize log_len; + GError *error = NULL; + GRegex *re; + GMatchInfo *match; + char *result = NULL; + + { + const char *display; + + display = g_getenv ("DISPLAY"); + if (!display) + return NULL; + + re = g_regex_new ("^:([0-9]+)", 0, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, display, 0, &match); + + if (!g_match_info_matches (match)) + { + g_regex_unref (re); + g_match_info_free (match); + return NULL; + } + + display_num = g_match_info_fetch (match, 1); + + g_regex_unref (re); + re = NULL; + g_match_info_free (match); + match = NULL; + } + + log_path = g_strdup_printf ("/var/log/Xorg.%s.log", display_num); + g_free (display_num); + log_contents = NULL; + g_file_get_contents (log_path, &log_contents, &log_len, &error); + g_free (log_path); + if (!log_contents) + return NULL; + + re = g_regex_new ("VESA VBE OEM Product: (.*)$", G_REGEX_MULTILINE, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, log_contents, 0, &match); + if (g_match_info_matches (match)) + { + char *tmp; + char *pretty_tmp; + tmp = g_match_info_fetch (match, 1); + pretty_tmp = prettify_info (tmp); + g_free (tmp); + /* Translators: VESA is an techncial acronym, don't translate it. */ + result = g_strdup_printf (_("VESA: %s"), pretty_tmp); + g_free (pretty_tmp); + } + g_match_info_free (match); + g_regex_unref (re); + + return result; +} + +static GraphicsData * +get_graphics_data (void) +{ + GraphicsData *result; + + result = g_slice_new0 (GraphicsData); + + result->glx_renderer = get_graphics_data_glx_renderer (); + result->xorg_vesa_hardware = get_graphics_data_xorg_vesa_hardware (); + + if (result->xorg_vesa_hardware != NULL) + result->hardware_string = result->xorg_vesa_hardware; + else if (result->glx_renderer != NULL) + result->hardware_string = result->glx_renderer; + else + result->hardware_string = _("Unknown"); + + return result; +} + +static gboolean +get_current_is_fallback (CcInfoPanel *self) +{ + GError *error; + GVariant *reply; + GVariant *reply_str; + gboolean is_fallback; + + error = NULL; + if (!(reply = g_dbus_connection_call_sync (self->priv->session_bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", "org.gnome.SessionManager", "session-name"), + (GVariantType*)"(v)", + 0, + -1, + NULL, &error))) + { + g_warning ("Failed to get fallback mode: %s", error->message); + g_clear_error (&error); + return FALSE; + } + + g_variant_get (reply, "(v)", &reply_str); + is_fallback = g_strcmp0 ("gnome-fallback", g_variant_get_string (reply_str, NULL)) == 0; + g_variant_unref (reply_str); + g_variant_unref (reply); + + return is_fallback; +} + +static void +cc_info_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_dispose (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->pk_proxy != NULL) + { + g_object_unref (priv->pk_proxy); + priv->pk_proxy = NULL; + } + + if (priv->pk_transaction_proxy != NULL) + { + g_object_unref (priv->pk_transaction_proxy); + priv->pk_transaction_proxy = NULL; + } + + if (priv->graphics_data != NULL) + { + graphics_data_free (priv->graphics_data); + priv->graphics_data = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->dispose (object); +} + +static void +cc_info_panel_finalize (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + priv->cancellable = NULL; + } + g_free (priv->gnome_version); + g_free (priv->gnome_date); + g_free (priv->gnome_distributor); + + if (priv->hostnamed_proxy != NULL) + { + g_object_unref (priv->hostnamed_proxy); + priv->hostnamed_proxy = NULL; + } + + if (priv->media_settings != NULL) + { + g_object_unref (priv->media_settings); + priv->media_settings = NULL; + } + + if (priv->session_settings != NULL) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->finalize (object); +} + +static void +cc_info_panel_class_init (CcInfoPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcInfoPanelPrivate)); + + object_class->get_property = cc_info_panel_get_property; + object_class->set_property = cc_info_panel_set_property; + object_class->dispose = cc_info_panel_dispose; + object_class->finalize = cc_info_panel_finalize; +} + +static char * +get_os_type (void) +{ + int bits; + + if (GLIB_SIZEOF_VOID_P == 8) + bits = 64; + else + bits = 32; + + /* translators: This is the type of architecture, for example: + * "64-bit" or "32-bit" */ + return g_strdup_printf (_("%d-bit"), bits); +} + +static void +query_done (GFile *file, + GAsyncResult *res, + CcInfoPanel *self) +{ + GFileInfo *info; + GError *error = NULL; + + self->priv->cancellable = NULL; + info = g_file_query_filesystem_info_finish (file, res, &error); + if (info != NULL) + { + self->priv->total_bytes += g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE); + g_object_unref (info); + } + else + { + char *path; + path = g_file_get_path (file); + g_warning ("Failed to get filesystem free space for '%s': %s", path, error->message); + g_free (path); + g_error_free (error); + } + + /* And onto the next element */ + get_primary_disc_info_start (self); +} + +static void +get_primary_disc_info_start (CcInfoPanel *self) +{ + GUnixMountEntry *mount; + GFile *file; + + if (self->priv->primary_mounts == NULL) + { + char *size; + GtkWidget *widget; + + size = g_format_size (self->priv->total_bytes); + widget = WID ("disk_label"); + gtk_label_set_text (GTK_LABEL (widget), size); + g_free (size); + + return; + } + + mount = self->priv->primary_mounts->data; + self->priv->primary_mounts = g_list_remove (self->priv->primary_mounts, mount); + file = g_file_new_for_path (g_unix_mount_get_mount_path (mount)); + g_unix_mount_free (mount); + + self->priv->cancellable = g_cancellable_new (); + + g_file_query_filesystem_info_async (file, + G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, + 0, + self->priv->cancellable, + (GAsyncReadyCallback) query_done, + self); + g_object_unref (file); +} + +static void +get_primary_disc_info (CcInfoPanel *self) +{ + GList *points; + GList *p; + + points = g_unix_mount_points_get (NULL); + for (p = points; p != NULL; p = p->next) + { + GUnixMountEntry *mount = p->data; + const char *mount_path; + + mount_path = g_unix_mount_get_mount_path (mount); + + if (gsd_should_ignore_unix_mount (mount) || + gsd_is_removable_mount (mount) || + g_str_has_prefix (mount_path, "/media/") || + g_str_has_prefix (mount_path, g_get_home_dir ())) + { + g_unix_mount_free (mount); + continue; + } + + self->priv->primary_mounts = g_list_prepend (self->priv->primary_mounts, mount); + } + g_list_free (points); + + get_primary_disc_info_start (self); +} + +static char * +remove_duplicate_whitespace (const char *old) +{ + char *new; + GRegex *re; + GError *error; + + error = NULL; + re = g_regex_new ("[ \t\n\r]+", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + new = g_regex_replace (re, + old, + -1, + 0, + " ", + 0, + &error); + g_regex_unref (re); + if (new == NULL) + { + g_warning ("Error replacing string: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + + return new; +} + + +static char * +get_cpu_info (const glibtop_sysinfo *info) +{ + GHashTable *counts; + GString *cpu; + char *ret; + GHashTableIter iter; + gpointer key, value; + int i; + int j; + + counts = g_hash_table_new (g_str_hash, g_str_equal); + + /* count duplicates */ + for (i = 0; i != info->ncpu; ++i) + { + const char * const keys[] = { "model name", "cpu" }; + char *model; + int *count; + + model = NULL; + + for (j = 0; model == NULL && j != G_N_ELEMENTS (keys); ++j) + { + model = g_hash_table_lookup (info->cpuinfo[i].values, + keys[j]); + } + + if (model == NULL) + model = _("Unknown model"); + + count = g_hash_table_lookup (counts, model); + if (count == NULL) + g_hash_table_insert (counts, model, GINT_TO_POINTER (1)); + else + g_hash_table_replace (counts, model, GINT_TO_POINTER (GPOINTER_TO_INT (count) + 1)); + } + + cpu = g_string_new (NULL); + g_hash_table_iter_init (&iter, counts); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + char *stripped; + int count; + + count = GPOINTER_TO_INT (value); + stripped = remove_duplicate_whitespace ((const char *)key); + if (count > 1) + g_string_append_printf (cpu, "%s \303\227 %d ", stripped, count); + else + g_string_append_printf (cpu, "%s ", stripped); + g_free (stripped); + } + + g_hash_table_destroy (counts); + + ret = prettify_info (cpu->str); + g_string_free (cpu, TRUE); + + return ret; +} + +static void +on_section_changed (GtkTreeSelection *selection, + gpointer data) +{ + CcInfoPanel *self = CC_INFO_PANEL (data); + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gint *indices; + int index; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + + indices = gtk_tree_path_get_indices (path); + index = indices[0]; + + if (index >= 0) + { + g_object_set (G_OBJECT (WID ("notebook")), + "page", index, NULL); + } + + gtk_tree_path_free (path); +} + +static gboolean +switch_fallback_get_mapping (GValue *value, + GVariant *variant, + gpointer data) +{ + const char *setting; + + setting = g_variant_get_string (variant, NULL); + g_value_set_boolean (value, strcmp (setting, "gnome") != 0); + return TRUE; +} + +static void +toggle_fallback_warning_label (CcInfoPanel *self, + gboolean visible) +{ + GtkWidget *widget; + const char *text; + + widget = WID ("graphics_logout_warning_label"); + + if (self->priv->is_fallback) + text = _("The next login will attempt to use the standard experience."); + else + text = _("The next login will use the fallback mode intended for unsupported graphics hardware."); + + gtk_label_set_text (GTK_LABEL (widget), text); + + if (visible) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); +} + +static GVariant * +switch_fallback_set_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer data) +{ + CcInfoPanel *self = data; + gboolean is_set; + + is_set = g_value_get_boolean (value); + if (is_set != self->priv->is_fallback) + toggle_fallback_warning_label (self, TRUE); + else + toggle_fallback_warning_label (self, FALSE); + + return g_variant_new_string (is_set ? "gnome-fallback" : "gnome"); +} + +static void +info_panel_setup_graphics (CcInfoPanel *self) +{ + GtkWidget *widget; + GtkSwitch *sw; + char *text; + + widget = WID ("graphics_driver_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + self->priv->is_fallback = get_current_is_fallback (self); + if (self->priv->is_fallback) + { + /* translators: The hardware is not able to run GNOME 3's + * shell, so we use the GNOME "Fallback" session */ + text = g_strdup (C_("Experience", "Fallback")); + } + else + { + /* translators: The hardware is able to run GNOME 3's + * shell, also called "Standard" experience */ + text = g_strdup (C_("Experience", "Standard")); + } + widget = WID ("graphics_experience_label"); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("graphics_fallback_switch_box"); + sw = GTK_SWITCH (gtk_switch_new ()); + g_settings_bind_with_mapping (self->priv->session_settings, KEY_SESSION_NAME, + sw, "active", 0, + switch_fallback_get_mapping, + switch_fallback_set_mapping, self, NULL); + gtk_box_pack_start (GTK_BOX (widget), GTK_WIDGET (sw), FALSE, FALSE, 0); + gtk_widget_show_all (GTK_WIDGET (sw)); + widget = WID ("fallback-label"); + gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (sw)); +} + +static void +default_app_changed (GtkAppChooserButton *button, + CcInfoPanel *self) +{ + GAppInfo *info; + GError *error = NULL; + DefaultAppData *app_data; + int i; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (button)); + app_data = g_object_get_data (G_OBJECT (button), "cc-default-app-data"); + + if (g_app_info_set_as_default_for_type (info, app_data->content_type, &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for '%s': %s", + g_app_info_get_name (info), app_data->content_type, error->message); + g_error_free (error); + error = NULL; + } + + if (app_data->extra_type_filter) + { + const char *const *mime_types; + GPatternSpec *pattern; + + pattern = g_pattern_spec_new (app_data->extra_type_filter); + mime_types = g_app_info_get_supported_types (info); + + for (i = 0; mime_types[i]; i++) + { + if (!g_pattern_match_string (pattern, mime_types[i])) + continue; + + if (g_app_info_set_as_default_for_type (info, mime_types[i], &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for secondary " + "content type '%s': %s", + g_app_info_get_name (info), mime_types[i], error->message); + g_error_free (error); + } + } + + g_pattern_spec_free (pattern); + } + + g_object_unref (info); +} + +static void +info_panel_setup_default_app (CcInfoPanel *self, + DefaultAppData *data, + guint left_attach, + guint right_attach, + guint top_attach, + guint bottom_attach) +{ + GtkWidget *button; + GtkWidget *table; + GtkWidget *label; + + table = WID ("default_apps_table"); + + button = gtk_app_chooser_button_new (data->content_type); + g_object_set_data (G_OBJECT (button), "cc-default-app-data", data); + + gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (button), TRUE); + gtk_table_attach (GTK_TABLE (table), button, + left_attach, right_attach, + top_attach, bottom_attach, GTK_FILL, 0, 0, 0); + g_signal_connect (G_OBJECT (button), "changed", + G_CALLBACK (default_app_changed), self); + gtk_widget_show (button); + + label = WID(data->label); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), button); +} + +static DefaultAppData preferred_app_infos[] = { + /* for web, we need to support text/html, + application/xhtml+xml and x-scheme-handler/https, + hence the "*" pattern + */ + { "x-scheme-handler/http", "web-label", "*" }, + { "x-scheme-handler/mailto", "mail-label", NULL }, + { "text/calendar", "calendar-label", NULL }, + { "audio/x-vorbis+ogg", "music-label", "audio/*" }, + { "video/x-ogm+ogg", "video-label", "video/*" }, + { "image/jpeg", "photos-label", "image/*" } +}; + +static void +info_panel_setup_default_apps (CcInfoPanel *self) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(preferred_app_infos); i++) + { + info_panel_setup_default_app (self, &preferred_app_infos[i], + 1, 2, i, i+1); + } +} + +static char ** +remove_elem_from_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + if (g_strcmp0 (v[idx], s) == 0) { + continue; + } + + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static char ** +add_elem_to_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, g_strdup (s)); + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static int +media_panel_g_strv_find (char **strv, + const char *find_me) +{ + guint index; + + g_return_val_if_fail (find_me != NULL, -1); + + for (index = 0; strv[index] != NULL; ++index) { + if (g_strcmp0 (strv[index], find_me) == 0) { + return index; + } + } + + return -1; +} + +static void +autorun_get_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean *pref_start_app, + gboolean *pref_ignore, + gboolean *pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_return_if_fail (pref_start_app != NULL); + g_return_if_fail (pref_ignore != NULL); + g_return_if_fail (pref_open_folder != NULL); + + *pref_start_app = FALSE; + *pref_ignore = FALSE; + *pref_open_folder = FALSE; + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + if (x_content_start_app != NULL) { + *pref_start_app = media_panel_g_strv_find (x_content_start_app, x_content_type) != -1; + } + if (x_content_ignore != NULL) { + *pref_ignore = media_panel_g_strv_find (x_content_ignore, x_content_type) != -1; + } + if (x_content_open_folder != NULL) { + *pref_open_folder = media_panel_g_strv_find (x_content_open_folder, x_content_type) != -1; + } + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + g_strfreev (x_content_open_folder); +} + +static void +autorun_set_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean pref_start_app, + gboolean pref_ignore, + gboolean pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_assert (x_content_type != NULL); + + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + + x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type); + if (pref_start_app) { + x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app); + + x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type); + if (pref_ignore) { + x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore); + + x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type); + if (pref_open_folder) { + x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder); + + g_strfreev (x_content_open_folder); + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + +} + +static void +custom_item_activated_cb (GtkAppChooserButton *button, + const gchar *item, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button)); + + if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, FALSE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, TRUE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) { + autorun_set_preferences (self, content_type, + FALSE, TRUE, FALSE); + } + + g_free (content_type); +} + +static void +combo_box_changed_cb (GtkComboBox *combo_box, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + GAppInfo *info; + gchar *content_type; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + if (info == NULL) + return; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (combo_box)); + autorun_set_preferences (self, content_type, + TRUE, FALSE, FALSE); + g_app_info_set_as_default_for_type (info, content_type, NULL); + + g_object_unref (info); + g_free (content_type); +} + +static void +prepare_combo_box (CcInfoPanel *self, + GtkWidget *combo_box, + const gchar *heading) +{ + GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box); + gboolean pref_ask; + gboolean pref_start_app; + gboolean pref_ignore; + gboolean pref_open_folder; + GAppInfo *info; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser)); + + /* fetch preferences for this content type */ + autorun_get_preferences (self, content_type, + &pref_start_app, &pref_ignore, &pref_open_folder); + pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + /* append the separator only if we have >= 1 apps in the chooser */ + if (info != NULL) { + gtk_app_chooser_button_append_separator (app_chooser); + g_object_unref (info); + } + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK, + _("Ask what to do"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING, + _("Do nothing"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER, + _("Open folder"), + NULL); + + gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE); + gtk_app_chooser_button_set_heading (app_chooser, _(heading)); + + if (pref_ask) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK); + } else if (pref_ignore) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING); + } else if (pref_open_folder) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER); + } + + g_signal_connect (app_chooser, "changed", + G_CALLBACK (combo_box_changed_cb), self); + g_signal_connect (app_chooser, "custom-item-activated", + G_CALLBACK (custom_item_activated_cb), self); + + g_free (content_type); +} + +static void +other_type_combo_box_changed (GtkComboBox *combo_box, + CcInfoPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + char *x_content_type; + GtkWidget *action_container; + GtkWidget *action_label; + + x_content_type = NULL; + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) { + return; + } + + model = gtk_combo_box_get_model (combo_box); + if (model == NULL) { + return; + } + + gtk_tree_model_get (model, &iter, + 1, &x_content_type, + -1); + + action_container = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_container")); + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + } + + self->priv->other_application_combo = gtk_app_chooser_button_new (x_content_type); + gtk_box_pack_start (GTK_BOX (action_container), self->priv->other_application_combo, TRUE, TRUE, 0); + prepare_combo_box (self, self->priv->other_application_combo, NULL); + gtk_widget_show (self->priv->other_application_combo); + + action_label = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_label")); + + gtk_label_set_mnemonic_widget (GTK_LABEL (action_label), self->priv->other_application_combo); + + g_free (x_content_type); +} + +static void +on_extra_options_dialog_response (GtkWidget *dialog, + int response, + CcInfoPanel *self) +{ + gtk_widget_hide (dialog); + + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + self->priv->other_application_combo = NULL; + } +} + +static void +on_extra_options_button_clicked (GtkWidget *button, + CcInfoPanel *self) +{ + GtkWidget *dialog; + GtkWidget *combo_box; + + dialog = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "extra_options_dialog")); + combo_box = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_other_type_combobox")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Other Media")); + g_signal_connect (dialog, + "response", + G_CALLBACK (on_extra_options_dialog_response), + self); + g_signal_connect (dialog, + "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), + NULL); + /* update other_application_combo */ + other_type_combo_box_changed (GTK_COMBO_BOX (combo_box), self); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +info_panel_setup_media (CcInfoPanel *self) +{ + guint n; + GList *l, *content_types; + GtkWidget *other_type_combo_box; + GtkWidget *extras_button; + GtkListStore *other_type_list_store; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkBuilder *builder = self->priv->builder; + + struct { + const gchar *widget_name; + const gchar *content_type; + const gchar *heading; + } const defs[] = { + { "media_audio_cdda_combobox", "x-content/audio-cdda", N_("Select an application for audio CDs") }, + { "media_video_dvd_combobox", "x-content/video-dvd", N_("Select an application for video DVDs") }, + { "media_music_player_combobox", "x-content/audio-player", N_("Select an application to run when a music player is connected") }, + { "media_dcf_combobox", "x-content/image-dcf", N_("Select an application to run when a camera is connected") }, + { "media_software_combobox", "x-content/unix-software", N_("Select an application for software CDs") }, + }; + + struct { + const gchar *content_type; + const gchar *description; + } const other_defs[] = { + /* translators: these strings are duplicates of shared-mime-info + * strings, just here to fix capitalization of the English originals. + * If the shared-mime-info translation works for your language, + * simply leave these untranslated. + */ + { "x-content/audio-dvd", N_("audio DVD") }, + { "x-content/blank-bd", N_("blank Blu-ray disc") }, + { "x-content/blank-cd", N_("blank CD disc") }, + { "x-content/blank-dvd", N_("blank DVD disc") }, + { "x-content/blank-hddvd", N_("blank HD DVD disc") }, + { "x-content/video-bluray", N_("Blu-ray video disc") }, + { "x-content/ebook-reader", N_("e-book reader") }, + { "x-content/video-hddvd", N_("HD DVD video disc") }, + { "x-content/image-picturecd", N_("Picture CD") }, + { "x-content/video-svcd", N_("Super Video CD") }, + { "x-content/video-vcd", N_("Video CD") }, + { "x-content/win32-software", N_("Windows software") }, + { "x-content/software", N_("Software") } + }; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + prepare_combo_box (self, + GTK_WIDGET (gtk_builder_get_object (builder, defs[n].widget_name)), + defs[n].heading); + } + + other_type_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "media_other_type_combobox")); + + other_type_list_store = gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (other_type_list_store), + 1, GTK_SORT_ASCENDING); + + + content_types = g_content_types_get_registered (); + + for (l = content_types; l != NULL; l = l->next) { + char *content_type = l->data; + char *description = NULL; + + if (!g_str_has_prefix (content_type, "x-content/")) + continue; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + if (g_content_type_is_a (content_type, defs[n].content_type)) { + goto skip; + } + } + + for (n = 0; n < G_N_ELEMENTS (other_defs); n++) { + if (strcmp (content_type, other_defs[n].content_type) == 0) { + const gchar *s = other_defs[n].description; + if (s == _(s)) + description = g_content_type_get_description (content_type); + else + description = g_strdup (_(s)); + + break; + } + } + + if (description == NULL) { + g_debug ("Content type '%s' is missing from the info panel", content_type); + description = g_content_type_get_description (content_type); + } + + gtk_list_store_append (other_type_list_store, &iter); + + gtk_list_store_set (other_type_list_store, &iter, + 0, description, + 1, content_type, + -1); + g_free (description); + skip: + ; + } + + g_list_free_full (content_types, g_free); + + gtk_combo_box_set_model (GTK_COMBO_BOX (other_type_combo_box), + GTK_TREE_MODEL (other_type_list_store)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (other_type_combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (other_type_combo_box), renderer, + "text", 0, + NULL); + + g_signal_connect (other_type_combo_box, + "changed", + G_CALLBACK (other_type_combo_box_changed), + self); + + gtk_combo_box_set_active (GTK_COMBO_BOX (other_type_combo_box), 0); + + extras_button = GTK_WIDGET (gtk_builder_get_object (builder, "extra_options_button")); + g_signal_connect (extras_button, + "clicked", + G_CALLBACK (on_extra_options_button_clicked), + self); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + gtk_builder_get_object (self->priv->builder, "media_autorun_never_checkbutton"), + "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_handling_vbox")), + "sensitive", + G_SETTINGS_BIND_INVERT_BOOLEAN); +} + +static void +info_panel_setup_selector (CcInfoPanel *self) +{ + GtkTreeView *view; + GtkListStore *model; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + int section_name_column = 0; + + view = GTK_TREE_VIEW (WID ("overview_treeview")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + + model = gtk_list_store_new (1, G_TYPE_STRING); + gtk_tree_view_set_model (view, GTK_TREE_MODEL (model)); + g_object_unref (model); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_renderer_set_padding (renderer, 4, 4); + g_object_set (renderer, + "width-chars", 20, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes (_("Section"), + renderer, + "text", section_name_column, + NULL); + gtk_tree_view_append_column (view, column); + + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Overview"), + -1); + gtk_tree_selection_select_iter (selection, &iter); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Default Applications"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Removable Media"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Graphics"), + -1); + + g_signal_connect (selection, "changed", + G_CALLBACK (on_section_changed), self); + on_section_changed (selection, self); + + gtk_widget_show_all (GTK_WIDGET (view)); +} + +static char * +get_hostname_property (CcInfoPanel *self, + const char *property) +{ + GVariant *variant; + char *str; + + variant = g_dbus_proxy_get_cached_property (self->priv->hostnamed_proxy, + property); + if (!variant) + { + GError *error = NULL; + GVariant *inner; + + /* Work around systemd-hostname not sending us back + * the property value when changing values */ + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", "org.freedesktop.hostname1", property), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) + { + g_warning ("Failed to get property '%s': %s", property, error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (variant, "(v)", &inner); + str = g_variant_dup_string (inner, NULL); + g_variant_unref (variant); + } + else + { + str = g_variant_dup_string (variant, NULL); + g_variant_unref (variant); + } + + return str; +} + +static char * +info_panel_get_hostname (CcInfoPanel *self) +{ + char *str; + + str = get_hostname_property (self, "PrettyHostname"); + + /* Empty strings means that we need to fallback */ + if (str != NULL && + *str == '\0') + { + g_free (str); + str = get_hostname_property (self, "Hostname"); + } + + return str; +} + +static void +info_panel_set_hostname (CcInfoPanel *self, + const char *text) +{ + char *hostname; + GVariant *variant; + GError *error = NULL; + + g_debug ("Setting PrettyHostname to '%s'", text); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetPrettyHostname", + g_variant_new ("(sb)", text, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set PrettyHostname: %s", error->message); + g_error_free (error); + error = NULL; + } + else + { + g_variant_unref (variant); + } + + /* Set the static hostname */ + hostname = pretty_hostname_to_static (text, FALSE); + g_assert (hostname); + + g_debug ("Setting StaticHostname to '%s'", hostname); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set StaticHostname: %s", error->message); + g_error_free (error); + } + else + { + g_variant_unref (variant); + } + g_free (hostname); +} + +static void +text_changed_cb (GtkEntry *entry, + CcInfoPanel *self) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + info_panel_set_hostname (self, text); +} + +static void +info_panel_setup_hostname (CcInfoPanel *self, + GPermission *permission) +{ + char *str; + GtkWidget *entry; + GError *error = NULL; + + if (permission == NULL) + { + g_debug ("Will not show hostname, hostnamed not installed"); + return; + } + + entry = WID ("name_entry"); + + if (g_permission_get_allowed (permission) != FALSE) + { + g_debug ("Not allowed to change the hostname"); + gtk_widget_set_sensitive (entry, TRUE); + } + + self->priv->hostnamed_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + NULL, + &error); + + /* This could only happen if the policy file was installed + * but not hostnamed, which points to a system bug */ + if (self->priv->hostnamed_proxy == NULL) + { + g_debug ("Couldn't get hostnamed to start, bailing: %s", error->message); + g_error_free (error); + return; + } + + gtk_widget_show (WID ("label4")); + gtk_widget_show (entry); + + str = info_panel_get_hostname (self); + if (str != NULL) + gtk_entry_set_text (GTK_ENTRY (entry), str); + else + gtk_entry_set_text (GTK_ENTRY (entry), ""); + g_free (str); + + g_signal_connect (G_OBJECT (entry), "changed", + G_CALLBACK (text_changed_cb), self); +} + +static void +info_panel_setup_overview (CcInfoPanel *self) +{ + GtkWidget *widget; + gboolean res; + glibtop_mem mem; + const glibtop_sysinfo *info; + char *text; + GPermission *permission; + + permission = polkit_permission_new_sync ("org.freedesktop.hostname1.set-static-hostname", NULL, NULL, NULL); + /* Is hostnamed installed? */ + info_panel_setup_hostname (self, permission); + + res = load_gnome_version (&self->priv->gnome_version, + &self->priv->gnome_distributor, + &self->priv->gnome_date); + if (res) + { + widget = WID ("version_label"); + text = g_strdup_printf (_("Version %s"), self->priv->gnome_version); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); + } + + glibtop_get_mem (&mem); + text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS); + widget = WID ("memory_label"); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + info = glibtop_get_sysinfo (); + + widget = WID ("processor_label"); + text = get_cpu_info (info); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("os_type_label"); + text = get_os_type (); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + get_primary_disc_info (self); + + widget = WID ("graphics_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + widget = WID ("info_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + + refresh_update_button (self); +} + +static void +refresh_update_button (CcInfoPanel *self) +{ + GtkWidget *widget; + + widget = WID ("updates_button"); + if (widget == NULL) + return; + + switch (self->priv->updates_state) + { + case PK_NOT_AVAILABLE: + gtk_widget_set_visible (widget, FALSE); + break; + case UPDATES_AVAILABLE: + gtk_widget_set_sensitive (widget, TRUE); + gtk_button_set_label (GTK_BUTTON (widget), _("Install Updates")); + break; + case UPDATES_NOT_AVAILABLE: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("System Up-To-Date")); + break; + case CHECKING_UPDATES: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("Checking for Updates")); + break; + } +} + +static void +on_pk_transaction_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "Package") == 0) + { + self->priv->updates_state = UPDATES_AVAILABLE; + } + else if (g_strcmp0 (signal_name, "Finished") == 0) + { + if (self->priv->updates_state == CHECKING_UPDATES) + self->priv->updates_state = UPDATES_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "ErrorCode") == 0) + { + self->priv->updates_state = PK_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "Destroy") == 0) + { + g_object_unref (self->priv->pk_transaction_proxy); + self->priv->pk_transaction_proxy = NULL; + } +} + +static void +on_pk_get_updates_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + g_warning ("Error getting PackageKit updates list: %s", error->message); + g_error_free (error); + return; + } +} + +static void +on_pk_get_tid_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + char *tid; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) == FALSE) + g_warning ("Error getting PackageKit transaction ID: %s", error->message); + g_error_free (error); + return; + } + + g_variant_get (result, "(o)", &tid); + + self->priv->pk_transaction_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + tid, + "org.freedesktop.PackageKit.Transaction", + NULL, + NULL); + g_free (tid); + g_variant_unref (result); + + if (self->priv->pk_transaction_proxy == NULL) + { + g_warning ("Unable to get PackageKit transaction proxy object"); + return; + } + + g_signal_connect (self->priv->pk_transaction_proxy, + "g-signal", + G_CALLBACK (on_pk_transaction_signal), + self); + + g_dbus_proxy_call (self->priv->pk_transaction_proxy, + "GetUpdates", + g_variant_new ("(t)", 1), /* PK_FILTER_ENUM_NONE */ + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_updates_ready, + self); +} + +static void +refresh_updates (CcInfoPanel *self) +{ + self->priv->updates_state = CHECKING_UPDATES; + refresh_update_button (self); + + g_assert (self->priv->pk_proxy != NULL); + g_dbus_proxy_call (self->priv->pk_proxy, + "CreateTransaction", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_tid_ready, + self); +} + +static void +on_pk_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "UpdatesChanged") == 0) + { + refresh_updates (self); + } +} + +static void +on_updates_button_clicked (GtkWidget *widget, + CcInfoPanel *self) +{ + GError *error; + error = NULL; + g_spawn_command_line_async ("gpk-update-viewer", &error); + if (error != NULL) + { + g_warning ("unable to launch Software Updates: %s", error->message); + g_error_free (error); + } +} + +static void +cc_info_panel_init (CcInfoPanel *self) +{ + GError *error = NULL; + GtkWidget *widget; + + self->priv = INFO_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + self->priv->session_settings = g_settings_new (GNOME_SESSION_MANAGER_SCHEMA); + self->priv->media_settings = g_settings_new (MEDIA_HANDLING_SCHEMA); + + self->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + g_assert (self->priv->session_bus); + + self->priv->pk_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + "/org/freedesktop/PackageKit", + "org.freedesktop.PackageKit", + NULL, + NULL); + if (self->priv->pk_proxy == NULL) + { + g_warning ("Unable to get PackageKit proxy object"); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + GVariant *v; + guint32 major, minor, micro; + + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMajor"); + g_variant_get (v, "u", &major); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMinor"); + g_variant_get (v, "u", &minor); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMicro"); + g_variant_get (v, "u", µ); + g_variant_unref (v); + + if (major != 0 || minor != 8) + { + g_warning ("PackageKit version %u.%u.%u not supported", major, minor, micro); + g_clear_object (&self->priv->pk_proxy); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + g_signal_connect (self->priv->pk_proxy, + "g-signal", + G_CALLBACK (on_pk_signal), + self); + refresh_updates (self); + } + } + + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/info.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->graphics_data = get_graphics_data (); + + widget = WID ("updates_button"); + g_signal_connect (widget, "clicked", G_CALLBACK (on_updates_button_clicked), self); + + info_panel_setup_selector (self); + info_panel_setup_overview (self); + info_panel_setup_default_apps (self); + info_panel_setup_media (self); + info_panel_setup_graphics (self); +} + +void +cc_info_panel_register (GIOModule *module) +{ + cc_info_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_INFO_PANEL, + "info", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/06_handle_passwd_with_ldap.patch/panels/user-accounts/run-passwd.c gnome-control-center-3.6.3/.pc/06_handle_passwd_with_ldap.patch/panels/user-accounts/run-passwd.c --- gnome-control-center-3.6.3/.pc/06_handle_passwd_with_ldap.patch/panels/user-accounts/run-passwd.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/06_handle_passwd_with_ldap.patch/panels/user-accounts/run-passwd.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,770 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* run-passwd.c: this file is part of users-admin, a gnome-system-tools frontend + * for user administration. + * + * Copyright (C) 2002 Diego Gonzalez + * Copyright (C) 2006 Johannes H. Jensen + * Copyright (C) 2010 Milan Bouchet-Valat + * + * Written by: Diego Gonzalez + * Modified by: Johannes H. Jensen , + * Milan Bouchet-Valat . + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Most of this code originally comes from gnome-about-me-password.c, + * from gnome-control-center. + */ + +#include +#include + +#include +#include +#include +#include + +#if __sun +#include +#include +#endif + +#include "run-passwd.h" + +/* Passwd states */ +typedef enum { + PASSWD_STATE_NONE, /* Passwd is not asking for anything */ + PASSWD_STATE_AUTH, /* Passwd is asking for our current password */ + PASSWD_STATE_NEW, /* Passwd is asking for our new password */ + PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */ + PASSWD_STATE_DONE, /* Passwd succeeded but has not yet exited */ + PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */ +} PasswdState; + +struct PasswdHandler { + const char *current_password; + const char *new_password; + + /* Communication with the passwd program */ + GPid backend_pid; + + GIOChannel *backend_stdin; + GIOChannel *backend_stdout; + + GQueue *backend_stdin_queue; /* Write queue to backend_stdin */ + + /* GMainLoop IDs */ + guint backend_child_watch_id; /* g_child_watch_add (PID) */ + guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */ + + /* State of the passwd program */ + PasswdState backend_state; + gboolean changing_password; + + PasswdCallback auth_cb; + gpointer auth_cb_data; + + PasswdCallback chpasswd_cb; + gpointer chpasswd_cb_data; +}; + +/* Buffer size for backend output */ +#define BUFSIZE 64 + + +static GQuark +passwd_error_quark (void) +{ + static GQuark q = 0; + + if (q == 0) { + q = g_quark_from_static_string("passwd_error"); + } + + return q; +} + +/* Error handling */ +#define PASSWD_ERROR (passwd_error_quark ()) + + +static void +stop_passwd (PasswdHandler *passwd_handler); + +static void +free_passwd_resources (PasswdHandler *passwd_handler); + +static gboolean +io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler); + + +/* + * Spawning and closing of backend {{ + */ + +/* Child watcher */ +static void +child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler) +{ + if (WIFEXITED (status)) { + if (WEXITSTATUS (status) >= 255) { + g_warning ("Child exited unexpectedly"); + } + if (WEXITSTATUS (status) == 0) { + if (passwd_handler->backend_state == PASSWD_STATE_RETYPE) { + passwd_handler->backend_state = PASSWD_STATE_DONE; + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + NULL, + passwd_handler->auth_cb_data); + } + } + } + + free_passwd_resources (passwd_handler); +} + +static void +ignore_sigpipe (gpointer data) +{ + signal (SIGPIPE, SIG_IGN); +} + +/* Spawn passwd backend + * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ +static gboolean +spawn_passwd (PasswdHandler *passwd_handler, GError **error) +{ + gchar *argv[2]; + gchar **envp; + gint my_stdin, my_stdout, my_stderr; + + argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ + argv[1] = NULL; + + envp = g_get_environ (); + envp = g_environ_setenv (envp, "LC_ALL", "C", TRUE); + + if (!g_spawn_async_with_pipes (NULL, /* Working directory */ + argv, /* Argument vector */ + envp, /* Environment */ + G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ + ignore_sigpipe, /* Child setup */ + NULL, /* Data to child setup */ + &passwd_handler->backend_pid, /* PID */ + &my_stdin, /* Stdin */ + &my_stdout, /* Stdout */ + &my_stderr, /* Stderr */ + error)) { /* GError */ + + /* An error occured */ + free_passwd_resources (passwd_handler); + + g_strfreev (envp); + + return FALSE; + } + + g_strfreev (envp); + + /* 2>&1 */ + if (dup2 (my_stderr, my_stdout) == -1) { + /* Failed! */ + g_set_error_literal (error, + PASSWD_ERROR, + PASSWD_ERROR_BACKEND, + strerror (errno)); + + /* Clean up */ + stop_passwd (passwd_handler); + + return FALSE; + } + + /* Open IO Channels */ + passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin); + passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout); + + /* Set raw encoding */ + /* Set nonblocking mode */ + if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { + + /* Clean up */ + stop_passwd (passwd_handler); + return FALSE; + } + + /* Turn off buffering */ + g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE); + g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE); + + /* Add IO Channel watcher */ + passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout, + G_IO_IN | G_IO_PRI, + (GIOFunc) io_watch_stdout, passwd_handler); + + /* Add child watcher */ + passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler); + + /* Success! */ + + return TRUE; +} + +/* Stop passwd backend */ +static void +stop_passwd (PasswdHandler *passwd_handler) +{ + /* This is the standard way of returning from the dialog with passwd. + * If we return this way we can safely kill passwd as it has completed + * its task. + */ + + if (passwd_handler->backend_pid != -1) { + kill (passwd_handler->backend_pid, 9); + } + + /* We must run free_passwd_resources here and not let our child + * watcher do it, since it will access invalid memory after the + * dialog has been closed and cleaned up. + * + * If we had more than a single thread we'd need to remove + * the child watch before trying to kill the child. + */ + free_passwd_resources (passwd_handler); +} + +/* Clean up passwd resources */ +static void +free_passwd_resources (PasswdHandler *passwd_handler) +{ + GError *error = NULL; + + /* Remove the child watcher */ + if (passwd_handler->backend_child_watch_id != 0) { + + g_source_remove (passwd_handler->backend_child_watch_id); + + passwd_handler->backend_child_watch_id = 0; + } + + + /* Close IO channels (internal file descriptors are automatically closed) */ + if (passwd_handler->backend_stdin != NULL) { + + if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message); + g_error_free (error); + error = NULL; + } + + g_io_channel_unref (passwd_handler->backend_stdin); + passwd_handler->backend_stdin = NULL; + } + + if (passwd_handler->backend_stdout != NULL) { + + if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message); + g_error_free (error); + error = NULL; + } + + g_io_channel_unref (passwd_handler->backend_stdout); + + passwd_handler->backend_stdout = NULL; + } + + /* Remove IO watcher */ + if (passwd_handler->backend_stdout_watch_id != 0) { + + g_source_remove (passwd_handler->backend_stdout_watch_id); + + passwd_handler->backend_stdout_watch_id = 0; + } + + /* Close PID */ + if (passwd_handler->backend_pid != -1) { + + g_spawn_close_pid (passwd_handler->backend_pid); + + passwd_handler->backend_pid = -1; + } + + /* Clear backend state */ + passwd_handler->backend_state = PASSWD_STATE_NONE; +} + +/* + * }} Spawning and closing of backend + */ + +/* + * Backend communication code {{ + */ + +/* Write the first element of queue through channel */ +static void +io_queue_pop (GQueue *queue, GIOChannel *channel) +{ + gchar *buf; + gsize bytes_written; + GError *error = NULL; + + buf = g_queue_pop_head (queue); + + if (buf != NULL) { + + if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message); + g_error_free (error); + } + + /* Ensure passwords are cleared from memory */ + memset (buf, 0, strlen (buf)); + g_free (buf); + } +} + +/* Goes through the argument list, checking if one of them occurs in str + * Returns: TRUE as soon as an element is found to match, FALSE otherwise */ +static gboolean +is_string_complete (gchar *str, ...) +{ + va_list ap; + gchar *arg; + + if (strlen (str) == 0) { + return FALSE; + } + + va_start (ap, str); + + while ((arg = va_arg (ap, char *)) != NULL) { + if (strstr (str, arg) != NULL) { + va_end (ap); + return TRUE; + } + } + + va_end (ap); + + return FALSE; +} + +/* + * IO watcher for stdout, called whenever there is data to read from the backend. + * This is where most of the actual IO handling happens. + */ +static gboolean +io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler) +{ + static GString *str = NULL; /* Persistent buffer */ + + gchar buf[BUFSIZE]; /* Temporary buffer */ + gsize bytes_read; + GError *gio_error = NULL; /* Error returned by functions */ + GError *error = NULL; /* Error sent to callbacks */ + + gboolean reinit = FALSE; + + /* Initialize buffer */ + if (str == NULL) { + str = g_string_new (""); + } + + if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error) + != G_IO_STATUS_NORMAL) { + g_warning ("IO Channel read error: %s", gio_error->message); + g_error_free (gio_error); + + return TRUE; + } + + str = g_string_append_len (str, buf, bytes_read); + + /* In which state is the backend? */ + switch (passwd_handler->backend_state) { + case PASSWD_STATE_AUTH: + /* Passwd is asking for our current password */ + + if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) { + + if (strstr (str->str, "assword: ") != NULL) { + /* Authentication successful */ + + passwd_handler->backend_state = PASSWD_STATE_NEW; + + /* Trigger callback to update authentication status */ + if (passwd_handler->auth_cb) + passwd_handler->auth_cb (passwd_handler, + NULL, + passwd_handler->auth_cb_data); + + } else { + /* Authentication failed */ + + error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, + _("Authentication failed")); + + passwd_handler->changing_password = FALSE; + + /* This error can happen both while authenticating or while changing password: + * if chpasswd_cb is set, this means we're already changing password */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + error, + passwd_handler->auth_cb_data); + else if (passwd_handler->auth_cb) + passwd_handler->auth_cb (passwd_handler, + error, + passwd_handler->auth_cb_data); + + g_error_free (error); + } + + reinit = TRUE; + } + break; + case PASSWD_STATE_NEW: + /* Passwd is asking for our new password */ + + if (is_string_complete (str->str, "assword: ", NULL)) { + /* Advance to next state */ + passwd_handler->backend_state = PASSWD_STATE_RETYPE; + + /* Pop retyped password from queue and into IO channel */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + + reinit = TRUE; + } + break; + case PASSWD_STATE_RETYPE: + /* Passwd is asking for our retyped new password */ + + if (is_string_complete (str->str, + "successfully", + "short", + "longer", + "palindrome", + "dictionary", + "simple", + "simplistic", + "similar", + "case", + "different", + "wrapped", + "recovered", + "recent", + "unchanged", + "match", + "1 numeric or special", + "failure", + "DIFFERENT", + "BAD PASSWORD", + NULL)) { + + if (strstr (str->str, "successfully") != NULL) { + /* Hooray! */ + + passwd_handler->backend_state = PASSWD_STATE_DONE; + /* Trigger callback to update status */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + NULL, + passwd_handler->chpasswd_cb_data); + } + else { + /* Ohnoes! */ + + if (strstr (str->str, "recovered") != NULL) { + /* What does this indicate? + * "Authentication information cannot be recovered?" from libpam? */ + error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, + str->str); + } else if (strstr (str->str, "short") != NULL || + strstr (str->str, "longer") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password is too short")); + } else if (strstr (str->str, "palindrome") != NULL || + strstr (str->str, "simple") != NULL || + strstr (str->str, "simplistic") != NULL || + strstr (str->str, "dictionary") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password is too simple")); + } else if (strstr (str->str, "similar") != NULL || + strstr (str->str, "different") != NULL || + strstr (str->str, "case") != NULL || + strstr (str->str, "wrapped") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The old and new passwords are too similar")); + } else if (strstr (str->str, "recent") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password has already been used recently.")); + } else if (strstr (str->str, "1 numeric or special") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password must contain numeric or special characters")); + } else if (strstr (str->str, "unchanged") != NULL || + strstr (str->str, "match") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The old and new passwords are the same")); + } else if (strstr (str->str, "failure") != NULL) { + /* Authentication failure */ + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, + _("Your password has been changed since you initially authenticated!")); + } + else if (strstr (str->str, "DIFFERENT")) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password does not contain enough different characters")); + } + else { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, + _("Unknown error")); + } + + /* At this point, passwd might have exited, in which case + * child_watch_cb should clean up for us and remove this watcher. + * On some error conditions though, passwd just re-prompts us + * for our new password. */ + passwd_handler->backend_state = PASSWD_STATE_ERR; + + passwd_handler->changing_password = FALSE; + + /* Trigger callback to update status */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + error, + passwd_handler->chpasswd_cb_data); + + g_error_free (error); + + } + + reinit = TRUE; + + /* child_watch_cb should clean up for us now */ + } + break; + case PASSWD_STATE_NONE: + /* Passwd is not asking for anything yet */ + if (is_string_complete (str->str, "assword: ", NULL)) { + + /* If the user does not have a password set, + * passwd will immediately ask for the new password, + * so skip the AUTH phase */ + if (is_string_complete (str->str, "new", "New", NULL)) { + gchar *pw; + + passwd_handler->backend_state = PASSWD_STATE_NEW; + + /* since passwd didn't ask for our old password + * in this case, simply remove it from the queue */ + pw = g_queue_pop_head (passwd_handler->backend_stdin_queue); + g_free (pw); + + /* Pop the IO queue, i.e. send new password */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + + } else { + + passwd_handler->backend_state = PASSWD_STATE_AUTH; + + /* Pop the IO queue, i.e. send current password */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + } + + reinit = TRUE; + } + break; + default: + /* Passwd has returned an error */ + reinit = TRUE; + break; + } + + if (reinit) { + g_string_free (str, TRUE); + str = NULL; + } + + /* Continue calling us */ + return TRUE; +} + +/* + * }} Backend communication code + */ + +/* Adds the current password to the IO queue */ +static void +authenticate (PasswdHandler *passwd_handler) +{ + gchar *s; + + s = g_strdup_printf ("%s\n", passwd_handler->current_password); + + g_queue_push_tail (passwd_handler->backend_stdin_queue, s); +} + +/* Adds the new password twice to the IO queue */ +static void +update_password (PasswdHandler *passwd_handler) +{ + gchar *s; + + s = g_strdup_printf ("%s\n", passwd_handler->new_password); + + g_queue_push_tail (passwd_handler->backend_stdin_queue, s); + /* We need to allocate new space because io_queue_pop() g_free()s + * every element of the queue after it's done */ + g_queue_push_tail (passwd_handler->backend_stdin_queue, g_strdup (s)); +} + + +PasswdHandler * +passwd_init (void) +{ + PasswdHandler *passwd_handler; + + passwd_handler = g_new0 (PasswdHandler, 1); + + /* Initialize backend_pid. -1 means the backend is not running */ + passwd_handler->backend_pid = -1; + + /* Initialize IO Channels */ + passwd_handler->backend_stdin = NULL; + passwd_handler->backend_stdout = NULL; + + /* Initialize write queue */ + passwd_handler->backend_stdin_queue = g_queue_new (); + + /* Initialize watchers */ + passwd_handler->backend_child_watch_id = 0; + passwd_handler->backend_stdout_watch_id = 0; + + /* Initialize backend state */ + passwd_handler->backend_state = PASSWD_STATE_NONE; + passwd_handler->changing_password = FALSE; + + return passwd_handler; +} + +void +passwd_destroy (PasswdHandler *passwd_handler) +{ + g_queue_free (passwd_handler->backend_stdin_queue); + stop_passwd (passwd_handler); + g_free (passwd_handler); +} + +void +passwd_authenticate (PasswdHandler *passwd_handler, + const char *current_password, + PasswdCallback cb, + const gpointer user_data) +{ + GError *error = NULL; + + /* Don't stop if we've already started chaging password */ + if (passwd_handler->changing_password) + return; + + /* Clear data from possible previous attempts to change password */ + passwd_handler->new_password = NULL; + passwd_handler->chpasswd_cb = NULL; + passwd_handler->chpasswd_cb_data = NULL; + g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL); + g_queue_clear (passwd_handler->backend_stdin_queue); + + passwd_handler->current_password = current_password; + passwd_handler->auth_cb = cb; + passwd_handler->auth_cb_data = user_data; + + /* Spawn backend */ + stop_passwd (passwd_handler); + + if (!spawn_passwd (passwd_handler, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return; + } + + authenticate (passwd_handler); + + /* Our IO watcher should now handle the rest */ +} + +gboolean +passwd_change_password (PasswdHandler *passwd_handler, + const char *new_password, + PasswdCallback cb, + const gpointer user_data) +{ + GError *error = NULL; + + passwd_handler->changing_password = TRUE; + + passwd_handler->new_password = new_password; + passwd_handler->chpasswd_cb = cb; + passwd_handler->chpasswd_cb_data = user_data; + + /* Stop passwd if an error occured and it is still running */ + if (passwd_handler->backend_state == PASSWD_STATE_ERR) { + + /* Stop passwd, free resources */ + stop_passwd (passwd_handler); + } + + /* Check that the backend is still running, or that an error + * has occured but it has not yet exited */ + if (passwd_handler->backend_pid == -1) { + /* If it is not, re-run authentication */ + + /* Spawn backend */ + stop_passwd (passwd_handler); + + if (!spawn_passwd (passwd_handler, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return FALSE; + } + + /* Add current and new passwords to queue */ + authenticate (passwd_handler); + update_password (passwd_handler); + } else { + /* Only add new passwords to queue */ + update_password (passwd_handler); + } + + /* Pop new password through the backend. + * If user has no password, popping the queue would output current + * password, while 'passwd' is waiting for the new one. So wait for + * io_watch_stdout() to remove current password from the queue, + * and output the new one for us. + */ + if (passwd_handler->current_password) + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + + /* Our IO watcher should now handle the rest */ + + return TRUE; +} diff -Nru gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/cc-power-panel.c gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/cc-power-panel.c --- gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/cc-power-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/cc-power-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1095 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2010 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include + +#include "cc-power-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcPowerPanel, cc_power_panel) + +#define POWER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_POWER_PANEL, CcPowerPanelPrivate)) + +struct _CcPowerPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + UpClient *up_client; + GtkWidget *levelbar_primary; +}; + +enum +{ + ACTION_MODEL_TEXT, + ACTION_MODEL_VALUE, + ACTION_MODEL_SENSITIVE +}; + +static void +cc_power_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_dispose (GObject *object) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (object)->priv; + + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + if (priv->up_client != NULL) + { + g_object_unref (priv->up_client); + priv->up_client = NULL; + } + + G_OBJECT_CLASS (cc_power_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcPowerPanel *panel) +{ +} + +static const char * +cc_power_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/power"; +} + +static void +cc_power_panel_class_init (CcPowerPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcPowerPanelPrivate)); + + object_class->get_property = cc_power_panel_get_property; + object_class->set_property = cc_power_panel_set_property; + object_class->dispose = cc_power_panel_dispose; + + panel_class->get_help_uri = cc_power_panel_get_help_uri; +} + +static gchar * +get_timestring (guint64 time_secs) +{ + gchar* timestring = NULL; + gint hours; + gint minutes; + + /* Add 0.5 to do rounding */ + minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); + + if (minutes == 0) + { + timestring = g_strdup (_("Unknown time")); + return timestring; + } + + if (minutes < 60) + { + timestring = g_strdup_printf (ngettext ("%i minute", + "%i minutes", + minutes), minutes); + return timestring; + } + + hours = minutes / 60; + minutes = minutes % 60; + + if (minutes == 0) + { + timestring = g_strdup_printf (ngettext ( + "%i hour", + "%i hours", + hours), hours); + return timestring; + } + + /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" + * Swap order with "%2$s %2$i %1$s %1$i if needed */ + timestring = g_strdup_printf (_("%i %s %i %s"), + hours, ngettext ("hour", "hours", hours), + minutes, ngettext ("minute", "minutes", minutes)); + return timestring; +} + +static void +set_device_battery_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* clear the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_hide (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Charging - %s until fully charged"), + time_string); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low battery, %s remaining"), + time_string); + /* show the warning */ + gtk_widget_show (widget); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using battery power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Using battery power")); + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Empty")); + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device until we stumble upon the device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_ups_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* always show the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_show (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low UPS, %s remaining"), + time_string); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using UPS power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Caution low UPS")); + } + else + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Using UPS power")); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device as extra UPS devices are not possible */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_battery_additional (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + GtkWidget *widget; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + NULL, /* percentage */ + &state, + NULL /* time */); + + /* set the description */ + switch (state) + { + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is empty")); + break; + default: + break; + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_addon")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the addon device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_show (widget); +out: + g_free (details); +} + +static void +add_device_secondary (CcPowerPanel *panel, + GVariant *device, + guint *secondary_devices_cnt) +{ + CcPowerPanelPrivate *priv = panel->priv; + const gchar *icon_name = NULL; + gdouble percentage; + guint64 time; + UpDeviceKind kind; + UpDeviceState state; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *widget; + GString *status; + GString *description; + gboolean show_caution = FALSE; + + g_variant_get (device, + "(susdut)", + NULL, + &kind, + NULL, + &percentage, + &state, + &time); + + switch (kind) + { + case UP_DEVICE_KIND_UPS: + icon_name = "uninterruptible-power-supply"; + show_caution = TRUE; + break; + case UP_DEVICE_KIND_MOUSE: + icon_name = "input-mouse"; + break; + case UP_DEVICE_KIND_KEYBOARD: + icon_name = "input-keyboard"; + break; + case UP_DEVICE_KIND_TABLET: + icon_name = "input-tablet"; + break; + case UP_DEVICE_KIND_PDA: + icon_name = "pda"; + break; + case UP_DEVICE_KIND_PHONE: + icon_name = "phone"; + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + icon_name = "multimedia-player"; + break; + case UP_DEVICE_KIND_COMPUTER: + icon_name = "computer"; + show_caution = TRUE; + break; + default: + icon_name = "battery"; + break; + } + + switch (kind) + { + case UP_DEVICE_KIND_MOUSE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless mouse")); + break; + case UP_DEVICE_KIND_KEYBOARD: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless keyboard")); + break; + case UP_DEVICE_KIND_UPS: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Uninterruptible power supply")); + break; + case UP_DEVICE_KIND_PDA: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Personal digital assistant")); + break; + case UP_DEVICE_KIND_PHONE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Cellphone")); + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Media player")); + break; + case UP_DEVICE_KIND_TABLET: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Tablet")); + break; + case UP_DEVICE_KIND_COMPUTER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Computer")); + break; + default: + /* TRANSLATORS: secondary battery, misc */ + description = g_string_new (_("Battery")); + break; + } + g_string_prepend (description, ""); + g_string_append (description, ""); + + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: secondary battery */ + status = g_string_new(C_("Battery power", "Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 10 && show_caution) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Caution")); + } + else if (percentage < 30) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Low")); + } + else + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Good")); + } + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Empty")); + break; + default: + status = g_string_new (up_device_state_to_string (state)); + break; + } + g_string_prepend (status, ""); + g_string_append (status, ""); + + /* create the new widget */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_widget_set_hexpand (hbox, TRUE); + widget = gtk_image_new (); + gtk_misc_set_alignment (GTK_MISC (widget), 0.5f, 0.0f); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_DND); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), description->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), status->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_level_bar_new (); + gtk_widget_set_margin_right (widget, 32); + gtk_widget_set_margin_top (widget, 3); + gtk_level_bar_set_value (GTK_LEVEL_BAR (widget), percentage / 100.0f); + gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + /* add to the grid */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + + /* two devices wide */ + gtk_grid_attach (GTK_GRID (widget), hbox, + *secondary_devices_cnt % 2, + (*secondary_devices_cnt / 2) - 1, + 1, 1); + (*secondary_devices_cnt)++; + + /* show panel */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_show_all (widget); + + g_string_free (description, TRUE); + g_string_free (status, TRUE); +} + +static void +get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + CcPowerPanel *panel; + CcPowerPanelPrivate *priv; + gboolean got_primary = FALSE; + gboolean ups_as_primary_device = FALSE; + GError *error = NULL; + gsize n_devices; + GList *children; + GList *l; + GtkWidget *widget; + guint i; + guint secondary_devices_cnt = 0; + GVariant *child; + GVariant *result; + GVariant *untuple; + UpDeviceKind kind; + UpDeviceState state; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; /* Must exit before accessing freed memory */ + } + + panel = CC_POWER_PANEL (user_data); + priv = panel->priv; + + /* empty the secondary box */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (widget), l->data); + g_list_free (children); + + /* hide both panels initially */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_hide (widget); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_hide (widget); + + if (result == NULL) + { + g_printerr ("Error getting devices: %s\n", error->message); + g_error_free (error); + return; + } + + untuple = g_variant_get_child_value (result, 0); + n_devices = g_variant_n_children (untuple); + + /* first we look for a discharging UPS, which is promoted to the + * primary device if it's discharging. Otherwise we use the first + * listed laptop battery as the primary device */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + &state, + NULL); + if (kind == UP_DEVICE_KIND_UPS && + state == UP_DEVICE_STATE_DISCHARGING) + { + ups_as_primary_device = TRUE; + } + g_variant_unref (child); + } + + /* add the devices now we know the state-of-play */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + NULL, + NULL); + if (kind == UP_DEVICE_KIND_LINE_POWER) + { + /* do nothing */ + } + else if (kind == UP_DEVICE_KIND_UPS && ups_as_primary_device) + { + set_device_ups_primary (panel, child); + } + else if (kind == UP_DEVICE_KIND_BATTERY && !ups_as_primary_device) + { + if (!got_primary) + { + set_device_battery_primary (panel, child); + got_primary = TRUE; + } + else + { + set_device_battery_additional (panel, child); + } + } + else + { + add_device_secondary (panel, child, &secondary_devices_cnt); + } + g_variant_unref (child); + } + + g_variant_unref (untuple); + g_variant_unref (result); +} + +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (user_data)->priv; + + /* get the new state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GDBusProxy *proxy; + CcPowerPanelPrivate *priv; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* Access user_data after checking for error because user_data might be + disposed already. */ + priv = CC_POWER_PANEL (user_data)->priv; + priv->proxy = proxy; + + /* we want to change the primary device changes */ + g_signal_connect (priv->proxy, + "g-properties-changed", + G_CALLBACK (on_properties_changed), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly expand the dialog */ + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +combo_time_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both keys */ + g_settings_set_int (self->priv->gsd_settings, key, value); +} + +static void +combo_enum_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_enum (self->priv->gsd_settings, key, value); +} + +static void +disable_unavailable_combo_items (CcPowerPanel *self, + GtkComboBox *combo_box) +{ + gboolean enabled; + gboolean ret; + gint value_tmp; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkTreeModel *model; + + /* setup the renderer */ + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", ACTION_MODEL_TEXT, + "sensitive", ACTION_MODEL_SENSITIVE, + NULL); + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* disable any actions we cannot do */ + do + { + gtk_tree_model_get (model, &iter, + ACTION_MODEL_VALUE, &value_tmp, + -1); + switch (value_tmp) { + case GSD_POWER_ACTION_SUSPEND: + enabled = up_client_get_can_suspend (self->priv->up_client); + break; + case GSD_POWER_ACTION_HIBERNATE: + enabled = up_client_get_can_hibernate (self->priv->up_client); + break; + default: + enabled = TRUE; + } + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + ACTION_MODEL_SENSITIVE, enabled, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_value_for_combo (GtkComboBox *combo_box, gint value) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value_tmp; + gboolean ret; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* try to make the UI match the setting */ + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_ac_battery_ui_mode (CcPowerPanel *self) +{ + gboolean has_batteries = FALSE; + gboolean ret; + GError *error = NULL; + GPtrArray *devices; + guint i; + UpDevice *device; + UpDeviceKind kind; + CcPowerPanelPrivate *priv = self->priv; + + /* this is sync, but it's cached in the daemon and so quick */ + ret = up_client_enumerate_devices_sync (self->priv->up_client, NULL, &error); + if (!ret) + { + g_warning ("failed to get device list: %s", error->message); + g_error_free (error); + goto out; + } + + devices = up_client_get_devices (self->priv->up_client); + for (i=0; ilen; i++) + { + device = g_ptr_array_index (devices, i); + g_object_get (device, + "kind", &kind, + NULL); + if (kind == UP_DEVICE_KIND_BATTERY || + kind == UP_DEVICE_KIND_UPS) + { + has_batteries = TRUE; + break; + } + } + g_ptr_array_unref (devices); +out: + gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_critical"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_critical"), has_batteries); +} + +static gboolean +activate_link_cb (GtkLabel *label, gchar *uri, CcPowerPanel *self) +{ + CcShell *shell; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, uri, NULL, &error) == FALSE) + { + g_warning ("Failed to activate %s panel: %s", uri, error->message); + g_error_free (error); + } + return TRUE; +} + +static void +cc_power_panel_init (CcPowerPanel *self) +{ + GError *error; + GtkWidget *widget; + gint value; + char *text; + + self->priv = POWER_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/power.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + /* add levelbar */ + self->priv->levelbar_primary = GTK_WIDGET + (gtk_builder_get_object (self->priv->builder, "levelbar_primary")); + self->priv->cancellable = g_cancellable_new (); + + /* get initial icon state */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power", + self->priv->cancellable, + got_power_proxy_cb, + self); + + /* find out if there are any battery or UPS devices attached + * and setup UI accordingly */ + self->priv->up_client = up_client_new (); + set_ac_battery_ui_mode (self); + + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + g_signal_connect (self->priv->gsd_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + + /* auto-sleep time */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-ac-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_ac")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-ac-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-battery-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_battery")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-battery-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + + /* actions */ + value = g_settings_get_enum (self->priv->gsd_settings, "critical-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_critical")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "critical-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + /* set screen link */ + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "label_screen_settings")); + /* TRANSLATORS: this is a link to the "Brightness and Lock" control center panel */ + text = g_strdup_printf ("%s", + _("Tip: screen brightness affects how much power is used")); + gtk_label_set_markup (GTK_LABEL (widget), text); + g_free (text); + + g_signal_connect (widget, "activate-link", + G_CALLBACK (activate_link_cb), + self); + + widget = WID (self->priv->builder, "vbox_power"); + gtk_widget_reparent (widget, (GtkWidget *) self); +} + +void +cc_power_panel_register (GIOModule *module) +{ + cc_power_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_POWER_PANEL, + "power", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/power.ui gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/power.ui --- gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/power.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/11_power-configure_lid_action.patch/panels/power/power.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + Hibernate + 3 + True + + + Power off + 2 + True + + + + + + + + + + + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + Don't suspend + 0 + + + + + False + False + + + True + False + 12 + 3 + + + True + False + 53 + 60 + 24 + vertical + 6 + 12 + + + True + False + On battery power + center + + + + + + 1 + 0 + + + + + True + False + When plugged in + center + + + + + + 2 + 0 + + + + + True + False + end + Suspend when inactive for + + + 0 + 1 + + + + + True + False + liststore_time + True + + + + + + + 1 + 1 + + + + + 150 + True + False + liststore_time + True + + + + + + + 2 + 1 + + + + + True + False + end + When power is _critically low + True + combobox_critical + + + 0 + 2 + + + + + True + False + liststore_critical + + + 1 + 2 + + + + + False + False + 0 + + + + + True + False + 53 + 60 + vertical + 3 + + + True + False + 3 + + + True + False + dialog-warning-symbolic + + + False + True + 0 + + + + + True + False + 0 + 55 minutes until fully charged + + + True + True + 1 + + + + + True + False + 3 + + + True + False + 1 + gtk-info + + + False + True + 0 + + + + + True + False + 1 + Your secondary battery is empty + + + False + True + 1 + + + + + False + False + 2 + + + + + False + True + 0 + + + + + False + True + + + False + True + 1 + + + + + False + False + 1 + + + + + True + False + 53 + 40 + 0 + 0.49000000953674316 + 4 + Tip: <a href="moo">Screen Settings</a> affect how much power is used + True + False + + + False + False + 2 + + + + + True + False + 15 + vertical + 24 + + + True + False + + + False + True + 0 + + + + + True + False + 9 + 28 + 15 + 18 + 6 + True + + + + + + + + + False + True + 1 + + + + + False + False + 3 + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/cc-screen-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/cc-screen-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,562 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "cc-screen-panel.h" + +CC_PANEL_REGISTER (CcScreenPanel, cc_screen_panel) + +#define SCREEN_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SCREEN_PANEL, CcScreenPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +struct _CcScreenPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *session_settings; + GSettings *lockdown_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + gboolean setting_brightness; +}; + + +static void +cc_screen_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_dispose (GObject *object) +{ + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (object)->priv; + + if (priv->lock_settings) + { + g_object_unref (priv->lock_settings); + priv->lock_settings = NULL; + } + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->session_settings) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + G_OBJECT_CLASS (cc_screen_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "lock-delay") == FALSE) + return; +} + +static void +update_lock_screen_sensitivity (CcScreenPanel *self) +{ + GtkWidget *widget; + gboolean locked; + + widget = WID ("screen_lock_main_box"); + locked = g_settings_get_boolean (self->priv->lockdown_settings, "disable-lock-screen"); + gtk_widget_set_sensitive (widget, !locked); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "disable-lock-screen") == FALSE) + return; + + update_lock_screen_sensitivity (panel); +} + +static const char * +cc_screen_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/prefs-display"; +} + +static void +cc_screen_panel_class_init (CcScreenPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcScreenPanelPrivate)); + + object_class->get_property = cc_screen_panel_get_property; + object_class->set_property = cc_screen_panel_set_property; + object_class->dispose = cc_screen_panel_dispose; + + panel_class->get_help_uri = cc_screen_panel_get_help_uri; +} + +static void +set_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* not setting, so pay attention to changed signals */ + priv->setting_brightness = FALSE; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + g_printerr ("Error setting brightness: %s\n", error->message); + g_error_free (error); + return; + } +} + +static void +brightness_slider_value_changed_cb (GtkRange *range, gpointer user_data) +{ + guint percentage; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* do not loop */ + if (priv->setting_brightness) + return; + + priv->setting_brightness = TRUE; + + /* push this to g-p-m */ + percentage = (guint) gtk_range_get_value (range); + g_dbus_proxy_call (priv->proxy, + "SetPercentage", + g_variant_new ("(u)", + percentage), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + set_brightness_cb, + user_data); +} + +static void +get_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + guint brightness; + GtkRange *range; + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + /* We got cancelled, so we're probably exiting */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + gtk_widget_hide (WID ("screen_brightness_hscale")); + gtk_widget_hide (WID ("screen_auto_reduce_checkbutton")); + gtk_widget_hide (WID ("brightness-frame")); + g_object_set (G_OBJECT (WID ("turn-off-alignment")), "left-padding", 0, NULL); + + if (error->message && + strstr (error->message, "No backlight devices present") == NULL) + { + g_warning ("Error getting brightness: %s", error->message); + } + g_error_free (error); + return; + } + + /* set the slider */ + g_variant_get (result, + "(u)", + &brightness); + range = GTK_RANGE (WID ("screen_brightness_hscale")); + gtk_range_set_range (range, 0, 100); + gtk_range_set_increments (range, 1, 10); + gtk_range_set_value (range, brightness); + g_signal_connect (range, + "value-changed", + G_CALLBACK (brightness_slider_value_changed_cb), + user_data); + g_variant_unref (result); +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + if (g_strcmp0 (signal_name, "Changed") == 0) + { + /* changed, but ignoring */ + if (self->priv->setting_brightness) + return; + + /* retrieve the value again from g-s-d */ + g_dbus_proxy_call (self->priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + self->priv->cancellable, + get_brightness_cb, + user_data); + } +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (priv->proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* we want to change the bar if the user presses brightness buttons */ + g_signal_connect (priv->proxy, + "g-signal", + G_CALLBACK (on_signal), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + priv->cancellable, + get_brightness_cb, + user_data); +} + +static void +set_idle_delay_from_dpms (CcScreenPanel *self, + int value) +{ + guint off_delay; + + off_delay = 0; + + if (value > 0) + off_delay = (guint) value; + + g_settings_set (self->priv->session_settings, "idle-delay", "u", off_delay); +} + +static void +dpms_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); + g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + + set_idle_delay_from_dpms (self, value); +} + +static void +lock_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint delay; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &delay, + -1); + g_settings_set (self->priv->lock_settings, "lock-delay", "u", delay); +} + +static void +set_dpms_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the AC setting */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +set_lock_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the lock setting */ + g_settings_get (self->priv->lock_settings, "lock-delay", "u", &value); + + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +cc_screen_panel_init (CcScreenPanel *self) +{ + GError *error; + GtkWidget *widget; + + self->priv = SCREEN_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/screen.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->cancellable = g_cancellable_new (); + + /* get initial brightness version */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + self->priv->cancellable, + got_power_proxy_cb, + self); + + self->priv->lock_settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_signal_connect (self->priv->lock_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + self->priv->session_settings = g_settings_new ("org.gnome.desktop.session"); + self->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect (self->priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + /* bind the auto dim checkbox */ + widget = WID ("screen_auto_reduce_checkbutton"); + g_settings_bind (self->priv->gsd_settings, + "idle-dim-battery", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* display off time */ + widget = WID ("screen_brightness_combobox"); + set_dpms_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (dpms_combo_changed_cb), + self); + + /* bind the screen lock checkbox */ + widget = WID ("screen_lock_on_switch"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* lock time */ + widget = WID ("screen_lock_combobox"); + set_lock_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (lock_combo_changed_cb), + self); + + widget = WID ("screen_lock_hbox"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "sensitive", + G_SETTINGS_BIND_GET); + + widget = WID ("show_notifications_check"); + g_settings_bind (self->priv->lock_settings, + "show-notifications", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + update_lock_screen_sensitivity (self); + + widget = WID ("screen_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + g_object_set (self, "valign", GTK_ALIGN_START, NULL); +} + +void +cc_screen_panel_register (GIOModule *module) +{ + cc_screen_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SCREEN_PANEL, + "screen", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/screen.ui gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/screen.ui --- gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/screen.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/12_add_never_turn_screen_off.patch/panels/screen/screen.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,410 @@ + + + + + + + + + + + + + Screen turns off + 0 + + + 30 seconds + 30 + + + 1 minute + 60 + + + 2 minutes + 120 + + + 3 minutes + 180 + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + + + + + + + + + + + 1 minute + 60 + + + 2 minutes + 120 + + + 3 minutes + 180 + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + + + + + True + vertical + + + True + 10 + vertical + 12 + + + True + 0 + none + + + True + 6 + 12 + + + True + vertical + 6 + + + True + True + 0 + False + bottom + + + + + + True + True + 0 + + + + + _Dim screen to save power + True + True + False + False + True + True + + + False + True + 1 + + + + + + + + + True + False + Brightness + True + + + + + + + + False + True + 0 + + + + + True + False + 6 + 12 + + + True + False + 6 + + + True + False + 0 + _Turn screen off when inactive for: + True + screen_brightness_combobox + + + False + False + 0 + + + + + True + False + screen_brightness_liststore + + + False + False + 1 + + + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + + + True + False + + + True + True + + + + + + False + True + 0 + + + + + False + False + 0 + + + + + True + False + 6 + + + True + False + 0 + _Lock screen after: + True + screen_lock_combobox + + + False + False + 0 + + + + + True + lock_liststore + + + False + False + 1 + + + + + False + False + 1 + + + + + False + True + + + Don't lock when at home + True + True + False + False + 0 + True + + + True + True + 0 + + + + + Locations... + True + True + True + False + False + none + right + http://glade.gnome.org + + + False + True + 1 + + + + + True + True + 2 + + + + + True + False + + + True + True + 0 + Show _notifications when locked + True + + + True + True + 0 + + + + + True + True + 3 + + + + + + + + + True + False + Lock + True + + + + + + + + False + True + 2 + + + + + True + True + 0 + + + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/cc-display-panel.c gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/cc-display-panel.c --- gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/cc-display-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/cc-display-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2685 @@ +/* + * Copyright (C) 2007, 2008 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Soren Sandmann + * + */ + +#include +#include +#include +#include + +#include "cc-display-panel.h" + +#include +#include "scrollarea.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include +#include +#include +#include +#include +#include + +CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) + +#define DISPLAY_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DISPLAY_PANEL, CcDisplayPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +#define TOP_BAR_HEIGHT 10 + +#define CLOCK_SCHEMA "org.gnome.desktop.interface" +#define CLOCK_FORMAT_KEY "clock-format" + +/* The minimum supported size for the panel, see: + * http://live.gnome.org/Design/SystemSettings */ +#define MINIMUM_WIDTH 675 +#define MINIMUM_HEIGHT 530 + +enum { + TEXT_COL, + WIDTH_COL, + HEIGHT_COL, + RATE_COL, + SORT_COL, + ROTATION_COL, + NUM_COLS +}; + +struct _CcDisplayPanelPrivate +{ + GnomeRRScreen *screen; + GnomeRRConfig *current_configuration; + GnomeRRLabeler *labeler; + GnomeRROutputInfo *current_output; + + GSettings *clock_settings; + GtkBuilder *builder; + guint focus_id; + + GtkWidget *panel; + GtkWidget *current_monitor_event_box; + GtkWidget *current_monitor_label; + GtkWidget *monitor_switch; + GtkListStore *resolution_store; + GtkWidget *resolution_combo; + GtkWidget *rotation_combo; + GtkWidget *clone_checkbox; + GtkWidget *clone_label; + GtkWidget *show_icon_checkbox; + + /* We store the event timestamp when the Apply button is clicked */ + guint32 apply_button_clicked_timestamp; + + GtkWidget *area; + gboolean ignore_gui_changes; + gboolean dragging_top_bar; + + /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */ + GDBusProxy *proxy; +}; + +typedef struct +{ + int grab_x; + int grab_y; + int output_x; + int output_y; +} GrabInfo; + +static void rebuild_gui (CcDisplayPanel *self); +static void on_clone_changed (GtkWidget *box, gpointer data); +static gboolean output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config); +static void select_current_output_from_dialog_position (CcDisplayPanel *self); +static void monitor_switch_active_cb (GObject *object, GParamSpec *pspec, gpointer data); +static void get_geometry (GnomeRROutputInfo *output, int *w, int *h); +static void apply_configuration_returned_cb (GObject *proxy, GAsyncResult *res, gpointer data); +static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height); +static gboolean output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height); +static char *make_resolution_string (int width, int height); +static GObject *cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties); +static void on_screen_changed (GnomeRRScreen *scr, gpointer data); + +static void +cc_display_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_dispose (GObject *object) +{ + G_OBJECT_CLASS (cc_display_panel_parent_class)->dispose (object); +} + +static void +cc_display_panel_finalize (GObject *object) +{ + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + + self = CC_DISPLAY_PANEL (object); + + g_signal_handlers_disconnect_by_func (self->priv->screen, on_screen_changed, self); + g_object_unref (self->priv->screen); + g_object_unref (self->priv->builder); + + if (self->priv->clock_settings != NULL) + g_object_unref (self->priv->clock_settings); + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (shell != NULL) + { + toplevel = cc_shell_get_toplevel (shell); + if (toplevel != NULL) + g_signal_handler_disconnect (G_OBJECT (toplevel), + self->priv->focus_id); + } + + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + + G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); +} + +static const char * +cc_display_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/prefs-display"; +} + +static void +cc_display_panel_class_init (CcDisplayPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcDisplayPanelPrivate)); + + panel_class->get_help_uri = cc_display_panel_get_help_uri; + + object_class->constructor = cc_display_panel_constructor; + object_class->get_property = cc_display_panel_get_property; + object_class->set_property = cc_display_panel_set_property; + object_class->dispose = cc_display_panel_dispose; + object_class->finalize = cc_display_panel_finalize; +} + +static void +error_message (CcDisplayPanel *self, const char *primary_text, const char *secondary_text) +{ + GtkWidget *toplevel; + GtkWidget *dialog; + + if (self && self->priv->panel) + toplevel = gtk_widget_get_toplevel (self->priv->panel); + else + toplevel = NULL; + + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + + if (secondary_text) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static gboolean +should_show_resolution (gint output_width, + gint output_height, + gint width, + gint height) +{ + if (width >= MIN (output_width, MINIMUM_WIDTH) && + height >= MIN (output_height, MINIMUM_HEIGHT)) + { + return TRUE; + } + return FALSE; +} + +static void +on_screen_changed (GnomeRRScreen *scr, + gpointer data) +{ + GnomeRRConfig *current; + CcDisplayPanel *self = data; + + current = gnome_rr_config_new_current (self->priv->screen, NULL); + gnome_rr_config_ensure_primary (current); + + if (self->priv->current_configuration) + g_object_unref (self->priv->current_configuration); + + self->priv->current_configuration = current; + self->priv->current_output = NULL; + + if (self->priv->labeler) { + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + } + + self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); + if (gtk_widget_has_focus (self->priv->panel)) + gnome_rr_labeler_show (self->priv->labeler); + + select_current_output_from_dialog_position (self); +} + +static void +on_viewport_changed (FooScrollArea *scroll_area, + GdkRectangle *old_viewport, + GdkRectangle *new_viewport) +{ + foo_scroll_area_set_size (scroll_area, + new_viewport->width, + new_viewport->height); + + foo_scroll_area_invalidate (scroll_area); +} + +static void +layout_set_font (PangoLayout *layout, const char *font) +{ + PangoFontDescription *desc = + pango_font_description_from_string (font); + + if (desc) + { + pango_layout_set_font_description (layout, desc); + + pango_font_description_free (desc); + } +} + +static void +clear_combo (GtkWidget *widget) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + GtkListStore *store = GTK_LIST_STORE (model); + + gtk_list_store_clear (store); +} + +typedef struct +{ + const char *text; + gboolean found; + GtkTreeIter iter; +} ForeachInfo; + +static gboolean +foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + ForeachInfo *info = data; + char *text = NULL; + + gtk_tree_model_get (model, iter, TEXT_COL, &text, -1); + + g_assert (text != NULL); + + if (strcmp (info->text, text) == 0) + { + info->found = TRUE; + info->iter = *iter; + return TRUE; + } + + return FALSE; +} + +static void +add_key (GtkTreeModel *model, + const char *text, + gboolean preferred, + int width, int height, int rate, + GnomeRRRotation rotation) +{ + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + { + GtkTreeIter iter; + g_debug ("adding %s with rate %d Hz", text, rate); + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, -1, + TEXT_COL, text, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + SORT_COL, width * 10000 + height, + ROTATION_COL, rotation, + -1); + return; + } + + /* Look, the preferred output, replace the old one */ + if (preferred) + { + g_debug ("replacing %s with rate %d Hz (preferred mode)", text, rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + + { + int old_rate; + + gtk_tree_model_get (model, &info.iter, + RATE_COL, &old_rate, + -1); + + /* Higher refresh rate */ + if (rate > old_rate) + { + g_debug ("replacing %s with rate %d Hz (old rate: %d)", text, rate, old_rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + } + + g_debug ("not adding %s with rate %d Hz (higher rate already there)", text, rate); +} + +static void +add_mode (CcDisplayPanel *self, + GnomeRRMode *mode, + gint output_width, + gint output_height, + guint preferred_id) +{ + int width, height, rate; + + width = gnome_rr_mode_get_width (mode); + height = gnome_rr_mode_get_height (mode); + rate = gnome_rr_mode_get_freq (mode); + + if (should_show_resolution (output_width, output_height, width, height)) + { + char *text; + gboolean preferred; + + preferred = (gnome_rr_mode_get_id (mode) == preferred_id); + text = make_resolution_string (width, height); + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->resolution_combo)), + text, preferred, width, height, rate, -1); + g_free (text); + } +} + + + +static gboolean +combo_select (GtkWidget *widget, const char *text) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + return FALSE; + + gtk_combo_box_set_active_iter (box, &info.iter); + return TRUE; +} + +static GnomeRRMode ** +get_current_modes (CcDisplayPanel *self) +{ + GnomeRROutput *output; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + return gnome_rr_screen_list_clone_modes (self->priv->screen); + } + else + { + if (!self->priv->current_output) + return NULL; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + + if (!output) + return NULL; + + return gnome_rr_output_list_modes (output); + } +} + +static void +rebuild_rotation_combo (CcDisplayPanel *self) +{ + typedef struct + { + GnomeRRRotation rotation; + const char * name; + } RotationInfo; + static const RotationInfo rotations[] = { + { GNOME_RR_ROTATION_0, NC_("display panel, rotation", "Normal") }, + { GNOME_RR_ROTATION_90, NC_("display panel, rotation", "Counterclockwise") }, + { GNOME_RR_ROTATION_270, NC_("display panel, rotation", "Clockwise") }, + { GNOME_RR_ROTATION_180, NC_("display panel, rotation", "180 Degrees") }, + }; + const char *selection; + GnomeRRRotation current; + int i; + + clear_combo (self->priv->rotation_combo); + + gtk_widget_set_sensitive (self->priv->rotation_combo, + self->priv->current_output && gnome_rr_output_info_is_active (self->priv->current_output)); + + if (!self->priv->current_output) + return; + + current = gnome_rr_output_info_get_rotation (self->priv->current_output); + + selection = NULL; + for (i = 0; i < G_N_ELEMENTS (rotations); ++i) + { + const RotationInfo *info = &(rotations[i]); + + gnome_rr_output_info_set_rotation (self->priv->current_output, info->rotation); + + /* NULL-GError --- FIXME: we should say why this rotation is not available! */ + if (gnome_rr_config_applicable (self->priv->current_configuration, self->priv->screen, NULL)) + { + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->rotation_combo)), g_dpgettext2 (NULL, "display panel, rotation", info->name), FALSE, 0, 0, 0, info->rotation); + + if (info->rotation == current) + selection = g_dpgettext2 (NULL, "display panel, rotation", info->name); + } + } + + gnome_rr_output_info_set_rotation (self->priv->current_output, current); + + if (!(selection && combo_select (self->priv->rotation_combo, selection))) + gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->rotation_combo), 0); +} + +static int +count_active_outputs (CcDisplayPanel *self) +{ + int i, count = 0; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_active (outputs[i])) + count++; + } + + return count; +} + +#if 0 +static int +count_all_outputs (GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) + ; + + return i; +} +#endif + +/* Computes whether "Mirror displays" (clone mode) is supported based on these criteria: + * + * 1. There is an available size for cloning. + * + * 2. There are 2 or more connected outputs that support that size. + */ +static gboolean +mirror_screens_is_supported (CcDisplayPanel *self) +{ + int clone_width, clone_height; + gboolean have_clone_size; + gboolean mirror_is_supported; + + mirror_is_supported = FALSE; + + have_clone_size = get_clone_size (self->priv->screen, &clone_width, &clone_height); + + if (have_clone_size) { + int i; + int num_outputs_with_clone_size; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + num_outputs_with_clone_size = 0; + + for (i = 0; outputs[i] != NULL; i++) + { + /* We count the connected outputs that support the clone size. It + * doesn't matter if those outputs aren't actually On currently; we + * will turn them on in on_clone_changed(). + */ + if (gnome_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (self, outputs[i], clone_width, clone_height)) + num_outputs_with_clone_size++; + } + + if (num_outputs_with_clone_size >= 2) + mirror_is_supported = TRUE; + } + + return mirror_is_supported; +} + +static void +rebuild_mirror_screens (CcDisplayPanel *self) +{ + gboolean mirror_is_active; + gboolean mirror_is_supported; + + g_signal_handlers_block_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); + + mirror_is_active = self->priv->current_configuration && gnome_rr_config_get_clone (self->priv->current_configuration); + + /* If mirror_is_active, then it *must* be possible to turn mirroring off */ + mirror_is_supported = mirror_is_active || mirror_screens_is_supported (self); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox), mirror_is_active); + gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); + gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); + + g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); +} + +static char * +mirror_monitor_name (void) +{ + /* Keep this string in sync with gnome-desktop/libgnome-desktop/gnome-rr-labeler.c */ + + /* Translators: this is the feature where what you see on your laptop's + * screen is the same as your external projector. Here, "Mirrored" is being + * used as an adjective. For example, the Spanish translation could be + * "Pantallas en Espejo". + */ + return g_strdup (_("Mirrored Displays")); +} + +static void +rebuild_current_monitor_label (CcDisplayPanel *self) +{ + char *str, *tmp; + GdkRGBA color; + gboolean use_color; + + if (self->priv->current_output) + { + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + tmp = mirror_monitor_name (); + else + tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); + + str = g_strdup_printf ("%s", tmp); + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); + use_color = TRUE; + g_free (tmp); + } + else + { + str = g_strdup_printf ("%s", _("Monitor")); + use_color = FALSE; + } + + gtk_label_set_markup (GTK_LABEL (self->priv->current_monitor_label), str); + g_free (str); + + if (use_color) + { + GdkRGBA black = { 0, 0, 0, 1.0 }; + + gtk_widget_override_background_color (self->priv->current_monitor_event_box, + gtk_widget_get_state_flags (self->priv->current_monitor_event_box), + &color); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + &black); + } + else + { + /* Remove any modifications we did on the label's color */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + NULL); + } + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (self->priv->current_monitor_event_box), use_color); +} + +static void +rebuild_on_off_radios (CcDisplayPanel *self) +{ + gboolean sensitive; + gboolean on_active; + + g_signal_handlers_block_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); + + sensitive = FALSE; + on_active = FALSE; + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && self->priv->current_output) + { + if (count_active_outputs (self) > 1 || !gnome_rr_output_info_is_active (self->priv->current_output)) + sensitive = TRUE; + else + sensitive = FALSE; + + on_active = gnome_rr_output_info_is_active (self->priv->current_output); + } + + gtk_widget_set_sensitive (self->priv->monitor_switch, sensitive); + + gtk_switch_set_active (GTK_SWITCH (self->priv->monitor_switch), on_active); + + g_signal_handlers_unblock_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); +} + +static char * +make_resolution_string (int width, int height) +{ + int ratio; + const char *aspect = NULL; + + if (width && height) { + if (width > height) + ratio = width * 10 / height; + else + ratio = height * 10 / width; + + switch (ratio) { + case 13: + aspect = "4:3"; + break; + case 16: + aspect = "16:10"; + break; + case 17: + aspect = "16:9"; + break; + case 12: + aspect = "5:4"; + break; + /* This catches 1.5625 as well (1600x1024) when maybe it shouldn't. */ + case 15: + aspect = "3:2"; + break; + case 18: + aspect = "9:5"; + break; + case 10: + aspect = "1:1"; + break; + } + } + + if (aspect != NULL) + return g_strdup_printf (_("%d x %d (%s)"), width, height, aspect); + else + return g_strdup_printf (_("%d x %d"), width, height); +} + +static void +find_best_mode (GnomeRRMode **modes, int *out_width, int *out_height) +{ + int i; + + *out_width = 0; + *out_height = 0; + + for (i = 0; modes[i] != NULL; i++) + { + int w, h; + + w = gnome_rr_mode_get_width (modes[i]); + h = gnome_rr_mode_get_height (modes[i]); + + if (w * h > *out_width * *out_height) + { + *out_width = w; + *out_height = h; + } + } +} + +static void +rebuild_resolution_combo (CcDisplayPanel *self) +{ + int i; + GnomeRRMode **modes; + GnomeRRMode *mode; + char *current; + int output_width, output_height; + guint32 preferred_id; + GnomeRROutput *output; + + clear_combo (self->priv->resolution_combo); + + if (!(modes = get_current_modes (self)) + || !self->priv->current_output + || !gnome_rr_output_info_is_active (self->priv->current_output)) + { + gtk_widget_set_sensitive (self->priv->resolution_combo, FALSE); + return; + } + + g_assert (self->priv->current_output != NULL); + + gnome_rr_output_info_get_geometry (self->priv->current_output, NULL, NULL, &output_width, &output_height); + g_assert (output_width != 0 && output_height != 0); + + gtk_widget_set_sensitive (self->priv->resolution_combo, TRUE); + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + mode = gnome_rr_output_get_preferred_mode (output); + preferred_id = gnome_rr_mode_get_id (mode); + + for (i = 0; modes[i] != NULL; ++i) + add_mode (self, modes[i], output_width, output_height, preferred_id); + + /* And force the preferred mode in the drop-down (when not in clone mode) + * https://bugzilla.gnome.org/show_bug.cgi?id=680969 */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration)) + add_mode (self, mode, output_width, output_height, preferred_id); + + current = make_resolution_string (output_width, output_height); + + if (!combo_select (self->priv->resolution_combo, current)) + { + int best_w, best_h; + char *str; + + find_best_mode (modes, &best_w, &best_h); + str = make_resolution_string (best_w, best_h); + combo_select (self->priv->resolution_combo, str); + g_free (str); + } + + g_free (current); +} + +static void +rebuild_gui (CcDisplayPanel *self) +{ + /* We would break spectacularly if we recursed, so + * just assert if that happens + */ + g_assert (self->priv->ignore_gui_changes == FALSE); + + self->priv->ignore_gui_changes = TRUE; + + rebuild_mirror_screens (self); + rebuild_current_monitor_label (self); + rebuild_on_off_radios (self); + rebuild_resolution_combo (self); + rebuild_rotation_combo (self); + + self->priv->ignore_gui_changes = FALSE; +} + +static gboolean +get_mode (GtkWidget *widget, int *width, int *height, int *rate, GnomeRRRotation *rot) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkComboBox *box = GTK_COMBO_BOX (widget); + int dummy; + + if (!gtk_combo_box_get_active_iter (box, &iter)) + return FALSE; + + if (!width) + width = &dummy; + + if (!height) + height = &dummy; + + if (!rate) + rate = &dummy; + + if (!rot) + rot = (GnomeRRRotation *)&dummy; + + model = gtk_combo_box_get_model (box); + gtk_tree_model_get (model, &iter, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + ROTATION_COL, rot, + -1); + + return TRUE; + +} + +static void +on_rotation_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + GnomeRRRotation rotation; + + if (!self->priv->current_output) + return; + + if (get_mode (self->priv->rotation_combo, NULL, NULL, NULL, &rotation)) + gnome_rr_output_info_set_rotation (self->priv->current_output, rotation); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +select_resolution_for_current_output (CcDisplayPanel *self) +{ + GnomeRRMode **modes; + int width, height; + int x,y; + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, NULL, NULL); + + width = gnome_rr_output_info_get_preferred_width (self->priv->current_output); + height = gnome_rr_output_info_get_preferred_height (self->priv->current_output); + + if (width != 0 && height != 0) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + return; + } + + modes = get_current_modes (self); + if (!modes) + return; + + find_best_mode (modes, &width, &height); + + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); +} + +static void +monitor_switch_active_cb (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + CcDisplayPanel *self = data; + gboolean value; + + if (!self->priv->current_output) + return; + + value = gtk_switch_get_active (GTK_SWITCH (object)); + + if (value) + { + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + select_resolution_for_current_output (self); + } + else + { + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + } + + rebuild_gui (self); + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +realign_outputs_after_resolution_change (CcDisplayPanel *self, GnomeRROutputInfo *output_that_changed, int old_width, int old_height) +{ + /* We find the outputs that were below or to the right of the output that + * changed, and realign them; we also do that for outputs that shared the + * right/bottom edges with the output that changed. The outputs that are + * above or to the left of that output don't need to change. + */ + + int i; + int old_right_edge, old_bottom_edge; + int dx, dy; + int x, y, width, height; + GnomeRROutputInfo **outputs; + + g_assert (self->priv->current_configuration != NULL); + + gnome_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height); + + if (width == old_width && height == old_height) + return; + + old_right_edge = x + old_width; + old_bottom_edge = y + old_height; + + dx = width - old_width; + dy = height - old_height; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; i++) + { + int output_x, output_y; + int output_width, output_height; + + if (outputs[i] == output_that_changed || !gnome_rr_output_info_is_connected (outputs[i])) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (output_x >= old_right_edge) + output_x += dx; + else if (output_x + output_width == old_right_edge) + output_x = x + width - output_width; + + if (output_y >= old_bottom_edge) + output_y += dy; + else if (output_y + output_height == old_bottom_edge) + output_y = y + height - output_height; + + gnome_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height); + } +} + +static void +on_resolution_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + int old_width, old_height; + int x,y; + int width; + int height; + + if (!self->priv->current_output) + return; + + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, &old_width, &old_height); + + if (get_mode (self->priv->resolution_combo, &width, &height, NULL, NULL)) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + + if (width == 0 || height == 0) + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + else + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + } + + realign_outputs_after_resolution_change (self, self->priv->current_output, old_width, old_height); + + rebuild_rotation_combo (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +lay_out_outputs_horizontally (CcDisplayPanel *self) +{ + int i; + int x; + GnomeRROutputInfo **outputs; + + /* Lay out all the monitors horizontally when "mirror screens" is turned + * off, to avoid having all of them overlapped initially. We put the + * outputs turned off on the right-hand side. + */ + + x = 0; + + /* First pass, all "on" outputs */ + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + + /* Second pass, all the black screens */ + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + +} + +/* FIXME: this function is copied from gnome-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c. + * Do we need to put this function in gnome-desktop for public use? + */ +static gboolean +get_clone_size (GnomeRRScreen *screen, int *width, int *height) +{ + GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); + int best_w, best_h; + int i; + + best_w = 0; + best_h = 0; + + for (i = 0; modes[i] != NULL; ++i) { + GnomeRRMode *mode = modes[i]; + int w, h; + + w = gnome_rr_mode_get_width (mode); + h = gnome_rr_mode_get_height (mode); + + if (w * h > best_w * best_h) { + best_w = w; + best_h = h; + } + } + + if (best_w > 0 && best_h > 0) { + if (width) + *width = best_w; + if (height) + *height = best_h; + + return TRUE; + } + + return FALSE; +} + +static gboolean +output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height) +{ + GnomeRROutput *output; + GnomeRRMode **modes; + int i; + + if (!gnome_rr_output_info_is_connected (info)) + return FALSE; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, gnome_rr_output_info_get_name (info)); + if (!output) + return FALSE; + + modes = gnome_rr_output_list_modes (output); + + for (i = 0; modes[i]; i++) { + if (gnome_rr_mode_get_width (modes[i]) == width + && gnome_rr_mode_get_height (modes[i]) == height) + return TRUE; + } + + return FALSE; +} + +static void +on_clone_changed (GtkWidget *box, gpointer data) +{ + CcDisplayPanel *self = data; + + gnome_rr_config_set_clone (self->priv->current_configuration, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox))); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + int i; + int width, height; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + self->priv->current_output = outputs[i]; + break; + } + } + + /* Turn on all the connected screens that support the best clone mode. + * The user may hit "Mirror displays", but he shouldn't have to turn on + * all the required outputs as well. + */ + + get_clone_size (self->priv->screen, &width, &height); + + for (i = 0; outputs[i]; i++) { + int x, y; + if (output_info_supports_mode (self, outputs[i], width, height)) { + gnome_rr_output_info_set_active (outputs[i], TRUE); + gnome_rr_output_info_get_geometry (outputs[i], &x, &y, NULL, NULL); + gnome_rr_output_info_set_geometry (outputs[i], x, y, width, height); + } + } + } + else + { + if (output_overlaps (self->priv->current_output, self->priv->current_configuration)) + lay_out_outputs_horizontally (self); + } + + rebuild_gui (self); +} + +static void +apply_rotation_to_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + GnomeRRRotation rotation; + + rotation = gnome_rr_output_info_get_rotation (output); + if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270)) + { + int tmp; + tmp = *h; + *h = *w; + *w = tmp; + } +} + +static void +get_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + if (gnome_rr_output_info_is_active (output)) + { + gnome_rr_output_info_get_geometry (output, NULL, NULL, w, h); + } + else + { + *h = gnome_rr_output_info_get_preferred_height (output); + *w = gnome_rr_output_info_get_preferred_width (output); + } + + apply_rotation_to_geometry (output, w, h); +} + +#define SPACE 15 +#define MARGIN 15 + +static GList * +list_connected_outputs (CcDisplayPanel *self, int *total_w, int *total_h) +{ + int i, dummy; + GList *result = NULL; + GnomeRROutputInfo **outputs; + + if (!total_w) + total_w = &dummy; + if (!total_h) + total_h = &dummy; + + *total_w = 0; + *total_h = 0; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + int w, h; + + result = g_list_prepend (result, outputs[i]); + + get_geometry (outputs[i], &w, &h); + + *total_w += w; + *total_h += h; + } + } + + return g_list_reverse (result); +} + +static int +get_n_connected (CcDisplayPanel *self) +{ + GList *connected_outputs = list_connected_outputs (self, NULL, NULL); + int n = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + return n; +} + +static double +compute_scale (CcDisplayPanel *self) +{ + int available_w, available_h; + int total_w, total_h; + int n_monitors; + GdkRectangle viewport; + GList *connected_outputs; + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + + connected_outputs = list_connected_outputs (self, &total_w, &total_h); + + n_monitors = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; + available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; + + return MIN ((double)available_w / total_w, (double)available_h / total_h); +} + +typedef struct Edge +{ + GnomeRROutputInfo *output; + int x1, y1; + int x2, y2; +} Edge; + +typedef struct Snap +{ + Edge *snapper; /* Edge that should be snapped */ + Edge *snappee; + int dy, dx; +} Snap; + +static void +add_edge (GnomeRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges) +{ + Edge e; + + e.x1 = x1; + e.x2 = x2; + e.y1 = y1; + e.y2 = y2; + e.output = output; + + g_array_append_val (edges, e); +} + +static void +list_edges_for_output (GnomeRROutputInfo *output, GArray *edges) +{ + int x, y, w, h; + + gnome_rr_output_info_get_geometry (output, &x, &y, &w, &h); + + apply_rotation_to_geometry (output, &w, &h); + + /* Top, Bottom, Left, Right */ + add_edge (output, x, y, x + w, y, edges); + add_edge (output, x, y + h, x + w, y + h, edges); + add_edge (output, x, y, x, y + h, edges); + add_edge (output, x + w, y, x + w, y + h, edges); +} + +static void +list_edges (GnomeRRConfig *config, GArray *edges) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + list_edges_for_output (outputs[i], edges); + } +} + +static gboolean +overlap (int s1, int e1, int s2, int e2) +{ + return (!(e1 < s2 || s1 >= e2)); +} + +static gboolean +horizontal_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) + return FALSE; + + return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); +} + +static gboolean +vertical_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) + return FALSE; + + return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); +} + +static void +add_snap (GArray *snaps, Snap snap) +{ + if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) + g_array_append_val (snaps, snap); +} + +static void +add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) +{ + Snap snap; + + snap.snapper = snapper; + snap.snappee = snappee; + + if (horizontal_overlap (snapper, snappee)) + { + snap.dx = 0; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + } + else if (vertical_overlap (snapper, snappee)) + { + snap.dy = 0; + snap.dx = snappee->x1 - snapper->x1; + + add_snap (snaps, snap); + } + + /* Corner snaps */ + /* 1->1 */ + snap.dx = snappee->x1 - snapper->x1; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + + /* 1->2 */ + snap.dx = snappee->x2 - snapper->x1; + snap.dy = snappee->y2 - snapper->y1; + + add_snap (snaps, snap); + + /* 2->2 */ + snap.dx = snappee->x2 - snapper->x2; + snap.dy = snappee->y2 - snapper->y2; + + add_snap (snaps, snap); + + /* 2->1 */ + snap.dx = snappee->x1 - snapper->x2; + snap.dy = snappee->y1 - snapper->y2; + + add_snap (snaps, snap); +} + +static void +list_snaps (GnomeRROutputInfo *output, GArray *edges, GArray *snaps) +{ + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + if (edge->output != output) + add_edge_snaps (output_edge, edge, snaps); + } + } + } +} + +#if 0 +static void +print_edge (Edge *edge) +{ + g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); +} +#endif + +static gboolean +corner_on_edge (int x, int y, Edge *e) +{ + if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) + return TRUE; + + if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) + return TRUE; + + return FALSE; +} + +static gboolean +edges_align (Edge *e1, Edge *e2) +{ + if (corner_on_edge (e1->x1, e1->y1, e2)) + return TRUE; + + if (corner_on_edge (e2->x1, e2->y1, e1)) + return TRUE; + + return FALSE; +} + +static gboolean +output_is_aligned (GnomeRROutputInfo *output, GArray *edges) +{ + gboolean result = FALSE; + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + /* We are aligned if an output edge matches + * an edge of another output + */ + if (edge->output != output_edge->output) + { + if (edges_align (output_edge, edge)) + { + result = TRUE; + goto done; + } + } + } + } + } + done: + + return result; +} + +static void +get_output_rect (GnomeRROutputInfo *output, GdkRectangle *rect) +{ + gnome_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); + + apply_rotation_to_geometry (output, &rect->width, &rect->height); +} + +static gboolean +output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config) +{ + int i; + GdkRectangle output_rect; + GnomeRROutputInfo **outputs; + + g_assert (output != NULL); + + get_output_rect (output, &output_rect); + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (outputs[i] != output && gnome_rr_output_info_is_connected (outputs[i])) + { + GdkRectangle other_rect; + + get_output_rect (outputs[i], &other_rect); + if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gnome_rr_config_is_aligned (GnomeRRConfig *config, GArray *edges) +{ + int i; + gboolean result = TRUE; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + if (!output_is_aligned (outputs[i], edges)) + return FALSE; + + if (output_overlaps (outputs[i], config)) + return FALSE; + } + } + + return result; +} + +static gboolean +is_corner_snap (const Snap *s) +{ + return s->dx != 0 && s->dy != 0; +} + +static int +compare_snaps (gconstpointer v1, gconstpointer v2) +{ + const Snap *s1 = v1; + const Snap *s2 = v2; + int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); + int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); + int d; + + d = sv1 - sv2; + + /* This snapping algorithm is good enough for rock'n'roll, but + * this is probably a better: + * + * First do a horizontal/vertical snap, then + * with the new coordinates from that snap, + * do a corner snap. + * + * Right now, it's confusing that corner snapping + * depends on the distance in an axis that you can't actually see. + * + */ + if (d == 0) + { + if (is_corner_snap (s1) && !is_corner_snap (s2)) + return -1; + else if (is_corner_snap (s2) && !is_corner_snap (s1)) + return 1; + else + return 0; + } + else + { + return d; + } +} + +/* Sets a mouse cursor for a widget's window. As a hack, you can pass + * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's + * window's cursor to its default). + */ +static void +set_cursor (GtkWidget *widget, GdkCursorType type) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (type == GDK_BLANK_CURSOR) + cursor = NULL; + else + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); + + window = gtk_widget_get_window (widget); + + if (window) + gdk_window_set_cursor (window, cursor); + + if (cursor) + g_object_unref (cursor); +} + +static void +set_top_bar_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Drag to change primary display."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +on_top_bar_event (FooScrollArea *area, + FooScrollAreaEvent *event, + CcDisplayPanel *self) +{ + /* Ignore drops */ + if (event->type == FOO_DROP) + return; + + /* If the mouse is inside the top bar, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_HAND1); + + if (event->type == FOO_BUTTON_PRESS) + { + rebuild_gui (self); + set_top_bar_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + self->priv->dragging_top_bar = TRUE; + foo_scroll_area_begin_grab (area, (FooScrollAreaEventFunc) on_top_bar_event, self); + } + + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + self->priv->dragging_top_bar = FALSE; + set_top_bar_tooltip (self, FALSE); + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +set_monitors_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Select a monitor to change its properties; drag it to rearrange its placement."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +set_primary_output (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + int i; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); +} + +static void +on_output_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + GnomeRROutputInfo *output = data; + CcDisplayPanel *self = g_object_get_data (G_OBJECT (area), "panel"); + + if (event->type == FOO_DRAG_HOVER) + { + if (gnome_rr_output_info_is_active (output) && self->priv->dragging_top_bar) + set_primary_output (self, output); + return; + } + if (event->type == FOO_DROP) + { + /* Activate new primary? */ + return; + } + + /* If the mouse is inside the outputs, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_FLEUR); + + if (event->type == FOO_BUTTON_PRESS) + { + GrabInfo *info; + + self->priv->current_output = output; + + rebuild_gui (self); + set_monitors_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + int output_x, output_y; + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + + foo_scroll_area_begin_grab (area, on_output_event, data); + + info = g_new0 (GrabInfo, 1); + info->grab_x = event->x; + info->grab_y = event->y; + info->output_x = output_x; + info->output_y = output_y; + + g_object_set_data (G_OBJECT (output), "grab-info", info); + } + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); + double scale = compute_scale (self); + int old_x, old_y; + int width, height; + int new_x, new_y; + int i; + GArray *edges, *snaps, *new_edges; + + gnome_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height); + new_x = info->output_x + (event->x - info->grab_x) / scale; + new_y = info->output_y + (event->y - info->grab_y) / scale; + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); + new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + list_edges (self->priv->current_configuration, edges); + list_snaps (output, edges, snaps); + + g_array_sort (snaps, compare_snaps); + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + for (i = 0; i < snaps->len; ++i) + { + Snap *snap = &(g_array_index (snaps, Snap, i)); + GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + gnome_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height); + + g_array_set_size (new_edges, 0); + list_edges (self->priv->current_configuration, new_edges); + + if (gnome_rr_config_is_aligned (self->priv->current_configuration, new_edges)) + { + g_array_free (new_edges, TRUE); + break; + } + else + { + gnome_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height); + } + } + + g_array_free (new_edges, TRUE); + g_array_free (snaps, TRUE); + g_array_free (edges, TRUE); + + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + set_monitors_tooltip (self, FALSE); + + g_free (g_object_get_data (G_OBJECT (output), "grab-info")); + g_object_set_data (G_OBJECT (output), "grab-info", NULL); + +#if 0 + g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); +#endif + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +on_canvas_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + /* If the mouse exits the outputs, reset the cursor to the default. See + * on_output_event() for where we set the cursor to the movement cursor if + * it is over one of the outputs. + */ + set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); +} + +static PangoLayout * +get_display_name (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + PangoLayout *layout; + char *text; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + text = mirror_monitor_name (); + else + text = g_strdup (gnome_rr_output_info_get_display_name (output)); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + return layout; +} + +static void +paint_background (FooScrollArea *area, + cairo_t *cr) +{ + GdkRectangle viewport; + GtkWidget *widget; + GtkStyleContext *context; + GdkRGBA fg, bg; + + widget = GTK_WIDGET (area); + + foo_scroll_area_get_viewport (area, &viewport); + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg); + + cairo_set_source_rgba (cr, + (fg.red + bg.red) / 2, + (fg.green + bg.green) / 2, + (fg.blue + bg.blue) / 2, + (fg.alpha + bg.alpha) / 2); + + cairo_rectangle (cr, + viewport.x, viewport.y, + viewport.width, viewport.height); + + cairo_fill_preserve (cr); + + foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); + + cairo_set_source_rgba (cr, + 0.7 * bg.red, + 0.7 * bg.green, + 0.7 * bg.blue, + 0.7 * bg.alpha); + + cairo_stroke (cr); +} + +static void +color_shade (double *r, + double *g, + double *b, + double k) +{ + double h, s, v; + + gtk_rgb_to_hsv (*r, *g, *b, &h, &s, &v); + + s *= k; + if (s > 1.0) + s = 1.0; + else if (s < 0.0) + s = 0.0; + + v *= k; + if (v > 1.0) + v = 1.0; + else if (v < 0.0) + v = 0.0; + + gtk_hsv_to_rgb (h, s, v, r, g, b); +} + +static void +paint_output (CcDisplayPanel *self, cairo_t *cr, int i) +{ + int w, h; + double scale = compute_scale (self); + double x, y; + int output_x, output_y; + GnomeRRRotation rotation; + int total_w, total_h; + GList *connected_outputs = list_connected_outputs (self, &total_w, &total_h); + GnomeRROutputInfo *output = g_list_nth (connected_outputs, i)->data; + PangoLayout *layout = get_display_name (self, output); + PangoRectangle ink_extent, log_extent; + GdkRectangle viewport; + GdkRGBA output_color; + double r, g, b; + double available_w; + double factor; + + cairo_save (cr); + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + get_geometry (output, &w, &h); + +#if 0 + g_debug ("%s (%p) geometry %d %d %d primary=%d", output->name, output->name, + w, h, output->rate, output->primary); +#endif + + viewport.height -= 2 * MARGIN; + viewport.width -= 2 * MARGIN; + + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; + y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; + +#if 0 + g_debug ("scaled: %f %f", x, y); + + g_debug ("scale: %f", scale); + + g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5); +#endif + + cairo_translate (cr, + x + (w * scale + 0.5) / 2, + y + (h * scale + 0.5) / 2); + + /* rotation is already applied in get_geometry */ + + rotation = gnome_rr_output_info_get_rotation (output); + if (rotation & GNOME_RR_REFLECT_X) + cairo_scale (cr, -1, 1); + + if (rotation & GNOME_RR_REFLECT_Y) + cairo_scale (cr, 1, -1); + + cairo_translate (cr, + - x - (w * scale + 0.5) / 2, + - y - (h * scale + 0.5) / 2); + + if (output == self->priv->current_output) + { + GtkStyleContext *context; + GdkRGBA color; + + context = gtk_widget_get_style_context (self->priv->area); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); + + cairo_rectangle (cr, x - 2, y - 2, w * scale + 0.5 + 4, h * scale + 0.5 + 4); + + cairo_set_line_width (cr, 4); + cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5); + cairo_stroke (cr); + } + + cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); + cairo_clip_preserve (cr); + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); + r = output_color.red; + g = output_color.green; + b = output_color.blue; + + if (!gnome_rr_output_info_is_active (output)) + { + /* If the output is turned off, just darken the selected color */ + color_shade (&r, &g, &b, 0.4); + } + + cairo_set_source_rgba (cr, r, g, b, 1.0); + + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, on_output_event, output); + cairo_fill (cr); + + cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + + cairo_stroke (cr); + cairo_set_line_width (cr, 2); + + cairo_save (cr); + + layout_set_font (layout, "Sans 10"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */ + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + ((h * scale + 0.5) - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + if (gnome_rr_output_info_is_active (output)) + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + else + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + cairo_restore (cr); + + if (gnome_rr_output_info_get_primary (output)) + { + const char *clock_format; + char *text; + gboolean use_24; + GDateTime *dt; + GDesktopClockFormat value; + + /* top bar */ + cairo_rectangle (cr, x, y, w * scale + 0.5, TOP_BAR_HEIGHT); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + + cairo_fill (cr); + + /* clock */ + value = g_settings_get_enum (self->priv->clock_settings, CLOCK_FORMAT_KEY); + use_24 = value == G_DESKTOP_CLOCK_FORMAT_24H; + if (use_24) + clock_format = _("%a %R"); + else + clock_format = _("%a %l:%M %p"); + + dt = g_date_time_new_now_local (); + text = g_date_time_format (dt, clock_format); + g_date_time_unref (dt); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + layout_set_font (layout, "Sans 4"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + (TOP_BAR_HEIGHT - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + } + + cairo_restore (cr); +} + +static void +on_area_paint (FooScrollArea *area, + cairo_t *cr, + gpointer data) +{ + CcDisplayPanel *self = data; + GList *connected_outputs = NULL; + GList *list; + + paint_background (area, cr); + + if (!self->priv->current_configuration) + return; + + connected_outputs = list_connected_outputs (self, NULL, NULL); + + for (list = connected_outputs; list != NULL; list = list->next) + { + paint_output (self, cr, g_list_position (connected_outputs, list)); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + break; + } +} + +static void +make_text_combo (GtkWidget *widget, int sort_column) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkListStore *store = gtk_list_store_new ( + NUM_COLS, + G_TYPE_STRING, /* Text */ + G_TYPE_INT, /* Width */ + G_TYPE_INT, /* Height */ + G_TYPE_INT, /* Frequency */ + G_TYPE_INT, /* Width * Height */ + G_TYPE_INT); /* Rotation */ + + GtkCellRenderer *cell; + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget)); + + gtk_combo_box_set_model (box, GTK_TREE_MODEL (store)); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell, + "text", 0, + NULL); + + if (sort_column != -1) + { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + sort_column, + GTK_SORT_DESCENDING); + } +} + +static void +compute_virtual_size_for_configuration (GnomeRRConfig *config, int *ret_width, int *ret_height) +{ + int i; + int width, height; + int output_x, output_y, output_width, output_height; + GnomeRROutputInfo **outputs; + + width = height = 0; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) + { + if (gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + width = MAX (width, output_x + output_width); + height = MAX (height, output_y + output_height); + } + } + + *ret_width = width; + *ret_height = height; +} + +static void +check_required_virtual_size (CcDisplayPanel *self) +{ + int req_width, req_height; + int min_width, max_width; + int min_height, max_height; + + compute_virtual_size_for_configuration (self->priv->current_configuration, &req_width, &req_height); + + gnome_rr_screen_get_ranges (self->priv->screen, &min_width, &max_width, &min_height, &max_height); + +#if 0 + g_debug ("X Server supports:"); + g_debug ("min_width = %d, max_width = %d", min_width, max_width); + g_debug ("min_height = %d, max_height = %d", min_height, max_height); + + g_debug ("Requesting size of %dx%d", req_width, req_height); +#endif + + if (!(min_width <= req_width && req_width <= max_width + && min_height <= req_height && req_height <= max_height)) + { + /* FIXME: present a useful dialog, maybe even before the user tries to Apply */ +#if 0 + g_debug ("Your X server needs a larger Virtual size!"); +#endif + } +} + +static void +begin_version2_apply_configuration (CcDisplayPanel *self, GdkWindow *parent_window, guint32 timestamp) +{ + XID parent_window_xid; + GError *error = NULL; + + parent_window_xid = GDK_WINDOW_XID (parent_window); + + self->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/XRANDR", + "org.gnome.SettingsDaemon.XRANDR_2", + NULL, + &error); + if (self->priv->proxy == NULL) { + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_error_free (error); + return; + } + + g_dbus_proxy_call (self->priv->proxy, + "ApplyConfiguration", + g_variant_new ("(xx)", (gint64) parent_window_xid, (gint64) timestamp), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + apply_configuration_returned_cb, + self); +} + +static void +ensure_current_configuration_is_saved (void) +{ + GnomeRRScreen *rr_screen; + GnomeRRConfig *rr_config; + + /* Normally, gnome_rr_config_save() creates a backup file based on the + * old monitors.xml. However, if *that* file didn't exist, there is + * nothing from which to create a backup. So, here we'll save the + * current/unchanged configuration and then let our caller call + * gnome_rr_config_save() again with the new/changed configuration, so + * that there *will* be a backup file in the end. + */ + + rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL); /* NULL-GError */ + if (!rr_screen) + return; + + rr_config = gnome_rr_config_new_current (rr_screen, NULL); + gnome_rr_config_ensure_primary (rr_config); + gnome_rr_config_save (rr_config, NULL); /* NULL-GError */ + + g_object_unref (rr_config); + g_object_unref (rr_screen); +} + +static void +apply_configuration_returned_cb (GObject *proxy, + GAsyncResult *res, + gpointer data) +{ + CcDisplayPanel *self = data; + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if (error) + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_clear_error (&error); + if (result) + g_variant_unref (result); + + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + + gtk_widget_set_sensitive (self->priv->panel, TRUE); +} + +static gboolean +sanitize_and_save_configuration (CcDisplayPanel *self) +{ + GError *error; + + gnome_rr_config_sanitize (self->priv->current_configuration); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + + check_required_virtual_size (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); + + ensure_current_configuration_is_saved (); + + error = NULL; + if (!gnome_rr_config_save (self->priv->current_configuration, &error)) + { + error_message (self, _("Could not save the monitor configuration"), error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +static void +apply (CcDisplayPanel *self) +{ + GdkWindow *window; + + self->priv->apply_button_clicked_timestamp = gtk_get_current_event_time (); + + if (!sanitize_and_save_configuration (self)) + return; + + g_assert (self->priv->proxy == NULL); + + gtk_widget_set_sensitive (self->priv->panel, FALSE); + + window = gtk_widget_get_window (gtk_widget_get_toplevel (self->priv->panel)); + + begin_version2_apply_configuration (self, window, + self->priv->apply_button_clicked_timestamp); +} + +#if 0 +/* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */ +static gboolean +driver_is_randr_10 (GnomeRRConfig *config) +{ + /* In the Xorg code, see xserver/randr/rrinfo.c:RRScanOldConfig(). It gets + * called when the graphics driver doesn't support RANDR 1.2 yet, just 1.0. + * In that case, the X server's base code (which supports RANDR 1.2) will + * simulate having a single output called "default". For drivers that *do* + * support RANDR 1.2, the separate outputs will be named differently, we + * hope. + * + * This heuristic is courtesy of Dirk Mueller + * + * FIXME: however, we don't even check for XRRQueryVersion() returning 1.2, neither + * here nor in gnome-desktop/libgnomedesktop*.c. Do we need to check for that, + * or is gnome_rr_screen_new()'s return value sufficient? + */ + + return (count_all_outputs (config) == 1 && strcmp (gnome_rr_output_info_get_name (gnome_rr_config_get_outputs (config)[0]), "default") == 0); +} +#endif + +static void +on_detect_displays (GtkWidget *widget, gpointer data) +{ + CcDisplayPanel *self = data; + GError *error; + + error = NULL; + if (!gnome_rr_screen_refresh (self->priv->screen, &error)) { + if (error) { + error_message (self, _("Could not detect displays"), error->message); + g_error_free (error); + } + } +} + +static GnomeRROutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) +{ + int i; + int nearest_index; + int nearest_dist; + GnomeRROutputInfo **outputs; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + int dist_x, dist_y; + int output_x, output_y, output_width, output_height; + + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (x < output_x) + dist_x = output_x - x; + else if (x >= output_x + output_width) + dist_x = x - (output_x + output_width) + 1; + else + dist_x = 0; + + if (y < output_y) + dist_y = output_y - y; + else if (y >= output_y + output_height) + dist_y = y - (output_y + output_height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return outputs[nearest_index]; + else + return NULL; +} + +/* Gets the output that contains the largest intersection with the window. + * Logic stolen from gdk_screen_get_monitor_at_window(). + */ +static GnomeRROutputInfo * +get_output_for_window (GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + GnomeRROutputInfo **outputs; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + GdkRectangle output_rect, intersection; + + gnome_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); + + if (gnome_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +static void +dialog_toplevel_focus_changed (GtkWindow *window, + GParamSpec *pspec, + CcDisplayPanel *self) +{ + if (self->priv->labeler == NULL) + return; + if (gtk_window_has_toplevel_focus (window)) + gnome_rr_labeler_show (self->priv->labeler); + else + gnome_rr_labeler_hide (self->priv->labeler); +} + +static void +on_toplevel_realized (GtkWidget *widget, + CcDisplayPanel *self) +{ + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (widget)); + rebuild_gui (self); +} + +/* We select the current output, i.e. select the one being edited, based on + * which output is showing the configuration dialog. + */ +static void +select_current_output_from_dialog_position (CcDisplayPanel *self) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (self->priv->panel); + + if (gtk_widget_get_realized (toplevel)) { + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (toplevel)); + rebuild_gui (self); + } else { + g_signal_connect (toplevel, "realize", G_CALLBACK (on_toplevel_realized), self); + self->priv->current_output = NULL; + } +} + +/* This is a GtkWidget::map-event handler. We wait for the display-properties + * dialog to be mapped, and then we select the output which corresponds to the + * monitor on which the dialog is being shown. + */ +static gboolean +dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + CcDisplayPanel *self = data; + + select_current_output_from_dialog_position (self); + return FALSE; +} + +static void +cc_display_panel_init (CcDisplayPanel *self) +{ +} + +static GObject * +cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) +{ + GtkBuilder *builder; + GtkWidget *align; + GError *error; + GObject *obj; + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + gchar *objects[] = {"display-panel", NULL}; + + obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); + self = CC_DISPLAY_PANEL (obj); + self->priv = DISPLAY_PANEL_PRIVATE (self); + + error = NULL; + self->priv->builder = builder = gtk_builder_new (); + + if (!gtk_builder_add_objects_from_file (builder, UIDIR "/display-capplet.ui", objects, &error)) + { + g_warning ("Could not parse UI definition: %s", error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); + g_signal_connect (self->priv->screen, "changed", G_CALLBACK (on_screen_changed), self); + if (!self->priv->screen) + { + error_message (NULL, _("Could not get screen information"), error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->clock_settings = g_settings_new (CLOCK_SCHEMA); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + self->priv->focus_id = g_signal_connect (toplevel, "notify::has-toplevel-focus", + G_CALLBACK (dialog_toplevel_focus_changed), self); + + self->priv->panel = WID ("display-panel"); + g_signal_connect_after (self->priv->panel, "show", + G_CALLBACK (dialog_map_event_cb), self); + + self->priv->current_monitor_event_box = WID ("current_monitor_event_box"); + self->priv->current_monitor_label = WID ("current_monitor_label"); + + self->priv->monitor_switch = WID ("monitor_switch"); + g_signal_connect (self->priv->monitor_switch, "notify::active", + G_CALLBACK (monitor_switch_active_cb), self); + + self->priv->resolution_combo = WID ("resolution_combo"); + g_signal_connect (self->priv->resolution_combo, "changed", + G_CALLBACK (on_resolution_changed), self); + + self->priv->rotation_combo = WID ("rotation_combo"); + g_signal_connect (self->priv->rotation_combo, "changed", + G_CALLBACK (on_rotation_changed), self); + + self->priv->clone_checkbox = WID ("clone_checkbox"); + g_signal_connect (self->priv->clone_checkbox, "toggled", + G_CALLBACK (on_clone_changed), self); + + self->priv->clone_label = WID ("clone_resolution_warning_label"); + + g_signal_connect (WID ("detect_displays_button"), + "clicked", G_CALLBACK (on_detect_displays), self); + + make_text_combo (self->priv->resolution_combo, 4); + make_text_combo (self->priv->rotation_combo, -1); + + /* Scroll Area */ + self->priv->area = (GtkWidget *)foo_scroll_area_new (); + + g_object_set_data (G_OBJECT (self->priv->area), "panel", self); + + set_monitors_tooltip (self, FALSE); + + /* FIXME: this should be computed dynamically */ + foo_scroll_area_set_min_size (FOO_SCROLL_AREA (self->priv->area), 0, 200); + gtk_widget_show (self->priv->area); + g_signal_connect (self->priv->area, "paint", + G_CALLBACK (on_area_paint), self); + g_signal_connect (self->priv->area, "viewport_changed", + G_CALLBACK (on_viewport_changed), self); + + align = WID ("align"); + + gtk_container_add (GTK_CONTAINER (align), self->priv->area); + + on_screen_changed (self->priv->screen, self); + + g_signal_connect_swapped (WID ("apply_button"), + "clicked", G_CALLBACK (apply), self); + + gtk_widget_show (self->priv->panel); + gtk_container_add (GTK_CONTAINER (self), self->priv->panel); + + return obj; +} + +void +cc_display_panel_register (GIOModule *module) +{ + cc_display_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_DISPLAY_PANEL, + "display", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/display-capplet.ui gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/display-capplet.ui --- gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/display-capplet.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/51_unity_options_in_display_panel.patch/panels/display/display-capplet.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,311 @@ + + + + + + + + True + 10 + vertical + 12 + + + True + + + + + + 0 + + + + + True + 12 + + + True + vertical + 12 + + + True + 12 + + + True + + + True + 0 + 10 + 5 + Monitor + + + + + + + + False + False + 0 + + + + + True + 12 + + + True + True + False + True + + + False + False + 0 + + + + + False + False + end + 1 + + + + + False + False + 0 + + + + + True + 0 + 0 + 12 + + + True + 3 + 2 + 12 + 6 + + + True + + + + + + 1 + 2 + 2 + 3 + + + + + + + True + 1 + _Resolution + True + resolution_combo + + + + GTK_FILL + + + + + + True + 1 + R_otation + rotation_combo + True + + + + 1 + 2 + GTK_FILL + + + + + + True + + + 1 + 2 + + + + + + True + + + + 0 + + + + + 1 + 2 + 1 + 2 + + + + + + + + + + + False + 1 + + + + + 0 + + + + + True + + + + + + 1 + + + + + True + vertical + + + _Mirror displays + True + True + False + True + True + + + False + False + 0 + + + + + True + 0 + Note: may limit resolution options + + + + + + False + False + 1 + + + + + + + + + + + False + 2 + + + + + 1 + + + + + True + 10 + + + True + 6 + end + + + gtk-apply + True + True + True + True + True + + + False + False + 1 + + + + + _Detect Displays + True + True + True + True + + + False + False + end + 0 + True + + + + + + + False + False + 2 + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.c gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.c --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,605 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include + +#include "cc-common-language.h" + +#include "gdm-languages.h" + +static gint +cc_common_language_sort_languages (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) +{ + char *ca, *cb; + char *la, *lb; + gboolean sa, ula; + gboolean sb, ulb; + gint result; + + gtk_tree_model_get (model, a, + LOCALE_COL, &ca, + DISPLAY_LOCALE_COL, &la, + SEPARATOR_COL, &sa, + USER_LANGUAGE, &ula, + -1); + gtk_tree_model_get (model, b, + LOCALE_COL, &cb, + DISPLAY_LOCALE_COL, &lb, + SEPARATOR_COL, &sb, + USER_LANGUAGE, &ulb, + -1); + + /* Sort before and after separator first */ + if (sa && sb) + result = 0; + else if (sa) + result = ulb ? 1 : -1; + else if (sb) + result = ula ? -1 : 1; + + /* Sort user-languages first */ + else if (ula != ulb) { + if (ula) + result = -1; + else + result = 1; + } + + else if (!ca) + result = 1; + else if (!cb) + result = -1; + else + result = strcmp (la, lb); + + g_free (ca); + g_free (cb); + g_free (la); + g_free (lb); + + return result; +} + +static gboolean +iter_for_language (GtkTreeModel *model, + const gchar *lang, + GtkTreeIter *iter, + gboolean region) +{ + char *l; + char *name; + char *language; + + gtk_tree_model_get_iter_first (model, iter); + do { + gtk_tree_model_get (model, iter, LOCALE_COL, &l, -1); + if (g_strcmp0 (l, lang) == 0) { + g_free (l); + return TRUE; + } + g_free (l); + } while (gtk_tree_model_iter_next (model, iter)); + + name = gdm_normalize_language_name (lang); + if (name != NULL) { + if (region) { + language = gdm_get_region_from_name (name, NULL); + } + else { + language = gdm_get_language_from_name (name, NULL); + } + + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), + iter, + -1, + LOCALE_COL, name, + DISPLAY_LOCALE_COL, language, + -1); + g_free (name); + g_free (language); + return TRUE; + } + + return FALSE; +} + +gboolean +cc_common_language_get_iter_for_language (GtkTreeModel *model, + const gchar *lang, + GtkTreeIter *iter) +{ + return iter_for_language (model, lang, iter, FALSE); +} + +gboolean +cc_common_language_get_iter_for_region (GtkTreeModel *model, + const gchar *lang, + GtkTreeIter *iter) +{ + return iter_for_language (model, lang, iter, TRUE); +} + +gboolean +cc_common_language_has_font (const gchar *locale) +{ + const FcCharSet *charset; + FcPattern *pattern; + FcObjectSet *object_set; + FcFontSet *font_set; + gchar *language_code; + gboolean is_displayable; + + is_displayable = FALSE; + pattern = NULL; + object_set = NULL; + font_set = NULL; + + if (!gdm_parse_language_name (locale, &language_code, NULL, NULL, NULL)) + return FALSE; + + charset = FcLangGetCharSet ((FcChar8 *) language_code); + if (!charset) { + /* fontconfig does not know about this language */ + is_displayable = TRUE; + } + else { + /* see if any fonts support rendering it */ + pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL); + + if (pattern == NULL) + goto done; + + object_set = FcObjectSetCreate (); + + if (object_set == NULL) + goto done; + + font_set = FcFontList (NULL, pattern, object_set); + + if (font_set == NULL) + goto done; + + is_displayable = (font_set->nfont > 0); + } + + done: + if (font_set != NULL) + FcFontSetDestroy (font_set); + + if (object_set != NULL) + FcObjectSetDestroy (object_set); + + if (pattern != NULL) + FcPatternDestroy (pattern); + + g_free (language_code); + + return is_displayable; +} + +typedef struct +{ + GtkListStore *store; + GHashTable *user_langs; + gchar **languages; + gboolean regions; + gint position; +} AsyncLangData; + +static void +async_lang_data_free (AsyncLangData *data) +{ + g_object_unref (data->store); + g_hash_table_unref (data->user_langs); + g_strfreev (data->languages); + g_free (data); +} + +static gboolean +add_one_language (gpointer d) +{ + AsyncLangData *data = d; + char *name; + char *language; + GtkTreeIter iter; + + if (data->languages[data->position] == NULL) { + /* we are done */ + async_lang_data_free (data); + return FALSE; + } + + name = gdm_normalize_language_name (data->languages[data->position]); + if (g_hash_table_lookup (data->user_langs, name) != NULL) { + g_free (name); + goto next; + } + + if (!cc_common_language_has_font (data->languages[data->position])) { + g_free (name); + goto next; + } + + if (data->regions) { + language = gdm_get_region_from_name (name, NULL); + } + else { + language = gdm_get_language_from_name (name, NULL); + } + if (!language) { + g_debug ("Ignoring '%s' as a locale, because we couldn't figure the language name", name); + g_free (name); + goto next; + } + + /* Add separator between initial languages and new additions */ + if (g_object_get_data (G_OBJECT (data->store), "needs-separator")) { + GtkTreeIter iter; + + gtk_list_store_insert_with_values (GTK_LIST_STORE (data->store), + &iter, + -1, + LOCALE_COL, NULL, + DISPLAY_LOCALE_COL, "Don't show", + SEPARATOR_COL, TRUE, + USER_LANGUAGE, FALSE, + -1); + g_object_set_data (G_OBJECT (data->store), "needs-separator", NULL); + } + + gtk_list_store_insert_with_values (data->store, + &iter, + -1, + LOCALE_COL, name, + DISPLAY_LOCALE_COL, language, + -1); + + g_free (name); + g_free (language); + + next: + data->position++; + + return TRUE; +} + +guint +cc_common_language_add_available_languages (GtkListStore *store, + gboolean regions, + GHashTable *user_langs) +{ + AsyncLangData *data; + + data = g_new0 (AsyncLangData, 1); + + data->store = g_object_ref (store); + data->user_langs = g_hash_table_ref (user_langs); + data->languages = gdm_get_all_language_names (); + data->regions = regions; + data->position = 0; + + return gdk_threads_add_idle (add_one_language, data); +} + +gchar * +cc_common_language_get_current_language (void) +{ + gchar *language; + const gchar *locale; + + locale = (const gchar *) setlocale (LC_MESSAGES, NULL); + if (locale) + language = gdm_normalize_language_name (locale); + else + language = NULL; + + return language; +} + +static void +languages_foreach_cb (gpointer key, + gpointer value, + gpointer user_data) +{ + GtkListStore *store = (GtkListStore *) user_data; + const char *locale = (const char *) key; + const char *display_locale = (const char *) value; + GtkTreeIter iter; + + gtk_list_store_insert_with_values (store, + &iter, + -1, + LOCALE_COL, locale, + DISPLAY_LOCALE_COL, display_locale, + SEPARATOR_COL, FALSE, + USER_LANGUAGE, TRUE, + -1); +} + +static gboolean +separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gboolean is_sep; + + gtk_tree_model_get (model, iter, + SEPARATOR_COL, &is_sep, + -1); + + return is_sep; +} + +void +cc_common_language_setup_list (GtkWidget *treeview, + GHashTable *initial) +{ + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + GtkListStore *store; + + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "width-chars", 40, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes (NULL, cell, "text", DISPLAY_LOCALE_COL, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store), + cc_common_language_sort_languages, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (treeview), + separator_func, + NULL, NULL); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + + /* Add languages from the initial hashtable */ + g_hash_table_foreach (initial, (GHFunc) languages_foreach_cb, store); + + /* Mark the need for a separator if we had any languages added */ + if (initial != NULL && + g_hash_table_size (initial) > 0) { + g_object_set_data (G_OBJECT (store), "needs-separator", GINT_TO_POINTER (TRUE)); + } +} + +void +cc_common_language_select_current_language (GtkTreeView *treeview) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean cont; + char *lang; + gboolean found; + + lang = cc_common_language_get_current_language (); + g_debug ("Trying to select lang '%s' in treeview", lang); + model = gtk_tree_view_get_model (treeview); + found = FALSE; + cont = gtk_tree_model_get_iter_first (model, &iter); + while (cont) { + char *locale; + + gtk_tree_model_get (model, &iter, + LOCALE_COL, &locale, + -1); + if (locale != NULL && + g_str_equal (locale, lang)) { + GtkTreeSelection *selection; + + g_debug ("Found '%s' in treeview", locale); + + found = TRUE; + selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_select_iter (selection, &iter); + g_free (locale); + break; + } + g_free (locale); + + cont = gtk_tree_model_iter_next (model, &iter); + } + g_free (lang); + + if (found == FALSE) + g_warning ("Could not find current language '%s' in the treeview", lang); +} + +static void +add_other_users_language (GHashTable *ht) +{ + GVariant *variant; + GVariantIter *vi; + GError *error = NULL; + const char *str; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts", + NULL, + NULL); + + if (proxy == NULL) + return; + + variant = g_dbus_proxy_call_sync (proxy, + "ListCachedUsers", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) { + g_warning ("Failed to list existing users: %s", error->message); + g_error_free (error); + g_object_unref (proxy); + return; + } + g_variant_get (variant, "(ao)", &vi); + while (g_variant_iter_loop (vi, "o", &str)) { + GDBusProxy *user; + GVariant *props; + const char *lang; + char *name; + char *language; + + user = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + str, + "org.freedesktop.Accounts.User", + NULL, + &error); + if (user == NULL) { + g_warning ("Failed to get proxy for user '%s': %s", + str, error->message); + g_error_free (error); + error = NULL; + continue; + } + props = g_dbus_proxy_get_cached_property (user, "Language"); + lang = g_variant_get_string (props, NULL); + if (lang != NULL && *lang != '\0' && + cc_common_language_has_font (lang) && + gdm_language_has_translations (lang)) { + name = gdm_normalize_language_name (lang); + if (!g_hash_table_lookup (ht, name)) { + language = gdm_get_language_from_name (name, NULL); + g_hash_table_insert (ht, name, language); + } + else { + g_free (name); + } + } + g_variant_unref (props); + g_object_unref (user); + } + g_variant_iter_free (vi); + g_variant_unref (variant); + + g_object_unref (proxy); +} + +GHashTable * +cc_common_language_get_initial_languages (void) +{ + GHashTable *ht; + char *name; + char *language; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + /* Add some common languages first */ + g_hash_table_insert (ht, g_strdup ("en_US.utf8"), g_strdup (_("English"))); + if (gdm_language_has_translations ("en_GB")) + g_hash_table_insert (ht, g_strdup ("en_GB.utf8"), g_strdup (_("British English"))); + if (gdm_language_has_translations ("de") || + gdm_language_has_translations ("de_DE")) + g_hash_table_insert (ht, g_strdup ("de_DE.utf8"), g_strdup (_("German"))); + if (gdm_language_has_translations ("fr") || + gdm_language_has_translations ("fr_FR")) + g_hash_table_insert (ht, g_strdup ("fr_FR.utf8"), g_strdup (_("French"))); + if (gdm_language_has_translations ("es") || + gdm_language_has_translations ("es_ES")) + g_hash_table_insert (ht, g_strdup ("es_ES.utf8"), g_strdup (_("Spanish"))); + if (gdm_language_has_translations ("zh_CN")) + g_hash_table_insert (ht, g_strdup ("zh_CN.utf8"), g_strdup (_("Chinese (simplified)"))); + if (gdm_language_has_translations ("ru") || + gdm_language_has_translations ("ru_RU")) + g_hash_table_insert (ht, g_strdup ("ru_RU.utf8"), g_strdup (_("Russian"))); + if (gdm_language_has_translations ("ar") || + gdm_language_has_translations ("ar_EG")) + g_hash_table_insert (ht, g_strdup ("ar_EG.utf8"), g_strdup (_("Arabic"))); + + /* Add the languages used by other users on the system */ + add_other_users_language (ht); + + /* Add current locale */ + name = cc_common_language_get_current_language (); + if (g_hash_table_lookup (ht, name) == NULL) { + language = gdm_get_language_from_name (name, NULL); + g_hash_table_insert (ht, name, language); + } else { + g_free (name); + } + + return ht; +} + +GHashTable * +cc_common_language_get_initial_regions (const gchar *lang) +{ + GHashTable *ht; + char *language; + gchar **langs; + gint i; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + +#if 0 + /* Add some common regions */ + g_hash_table_insert (ht, g_strdup ("en_US.utf8"), g_strdup (_("United States"))); + g_hash_table_insert (ht, g_strdup ("de_DE.utf8"), g_strdup (_("Germany"))); + g_hash_table_insert (ht, g_strdup ("fr_FR.utf8"), g_strdup (_("France"))); + g_hash_table_insert (ht, g_strdup ("es_ES.utf8"), g_strdup (_("Spain"))); + g_hash_table_insert (ht, g_strdup ("zh_CN.utf8"), g_strdup (_("China"))); +#endif + + gdm_parse_language_name (lang, &language, NULL, NULL, NULL); + langs = gdm_get_all_language_names (); + for (i = 0; langs[i]; i++) { + gchar *l, *s; + gdm_parse_language_name (langs[i], &l, NULL, NULL, NULL); + if (g_strcmp0 (language, l) == 0) { + if (!g_hash_table_lookup (ht, langs[i])) { + s = gdm_get_region_from_name (langs[i], NULL); + g_hash_table_insert (ht, g_strdup (langs[i]), s); + } + } + g_free (l); + } + g_strfreev (langs); + g_free (language); + + return ht; +} diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.h gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.h --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.h 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-common-language.h 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#ifndef __CC_COMMON_LANGUAGE_H__ +#define __CC_COMMON_LANGUAGE_H__ + +#include + +G_BEGIN_DECLS + +enum { + LOCALE_COL, + DISPLAY_LOCALE_COL, + SEPARATOR_COL, + USER_LANGUAGE, + NUM_COLS +}; + +gboolean cc_common_language_get_iter_for_language (GtkTreeModel *model, + const gchar *lang, + GtkTreeIter *iter); +gboolean cc_common_language_get_iter_for_region (GtkTreeModel *model, + const gchar *lang, + GtkTreeIter *iter); +guint cc_common_language_add_available_languages (GtkListStore *store, + gboolean regions, + GHashTable *user_langs); +gboolean cc_common_language_has_font (const gchar *locale); +gchar *cc_common_language_get_current_language (void); + +GHashTable *cc_common_language_get_initial_languages (void); +GHashTable *cc_common_language_get_initial_regions (const gchar *lang); + +void cc_common_language_setup_list (GtkWidget *treeview, + GHashTable *initial); +void cc_common_language_select_current_language (GtkTreeView *treeview); + +G_END_DECLS + +#endif diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-language-chooser.c gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-language-chooser.c --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-language-chooser.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/cc-language-chooser.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,343 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include "cc-language-chooser.h" +#include "cc-common-language.h" +#include "gdm-languages.h" + +gchar * +cc_language_chooser_get_language (GtkWidget *chooser) +{ + GtkTreeView *tv; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *lang; + + tv = (GtkTreeView *) g_object_get_data (G_OBJECT (chooser), "list"); + selection = gtk_tree_view_get_selection (tv); + + gdk_threads_enter (); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (model, &iter, LOCALE_COL, &lang, -1); + else + lang = NULL; + gdk_threads_leave (); + + return lang; +} + +void +cc_language_chooser_clear_filter (GtkWidget *chooser) +{ + GtkEntry *entry; + + entry = (GtkEntry *) g_object_get_data (G_OBJECT (chooser), "filter-entry"); + gtk_entry_set_text (entry, ""); +} + +static void +row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkWidget *chooser) +{ + gtk_dialog_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK); +} + +static void +languages_foreach_cb (gpointer key, + gpointer value, + gpointer user_data) +{ + GtkListStore *store = (GtkListStore *) user_data; + const char *locale = (const char *) key; + const char *display_locale = (const char *) value; + GtkTreeIter iter; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + LOCALE_COL, locale, + DISPLAY_LOCALE_COL, display_locale, + -1); +} + +void +cc_add_user_languages (GtkTreeModel *model) +{ + char *name; + GtkTreeIter iter; + GtkListStore *store = GTK_LIST_STORE (model); + GHashTable *user_langs; + const char *display; + + gtk_list_store_clear (store); + + user_langs = cc_common_language_get_initial_languages (); + + /* Add the current locale first */ + name = cc_common_language_get_current_language (); + display = g_hash_table_lookup (user_langs, name); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, LOCALE_COL, name, DISPLAY_LOCALE_COL, display, -1); + g_hash_table_remove (user_langs, name); + g_free (name); + + /* The rest of the languages */ + g_hash_table_foreach (user_langs, (GHFunc) languages_foreach_cb, store); + + /* And now the "Other..." selection */ + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1); + + g_hash_table_destroy (user_langs); +} + +static void +remove_timeout (gpointer data, + GObject *where_the_object_was) +{ + guint timeout = GPOINTER_TO_UINT (data); + g_source_remove (timeout); +} + +static void +remove_async (gpointer data) +{ + guint async_id = GPOINTER_TO_UINT (data); + + g_source_remove (async_id); +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkWidget *chooser) +{ + gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), + GTK_RESPONSE_OK, + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static gboolean +finish_language_chooser (gpointer user_data) +{ + GtkWidget *chooser = (GtkWidget *) user_data; + GtkWidget *list; + GtkTreeModel *model; + GtkWindow *parent; + GHashTable *user_langs; + guint timeout; + guint async_id; + GtkTreeSelection *selection; + gboolean regions; + + /* Did we get called after the widget was destroyed? */ + if (chooser == NULL) + return FALSE; + + regions = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (chooser), "regions")); + + list = g_object_get_data (G_OBJECT (chooser), "list"); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + user_langs = g_object_get_data (G_OBJECT (chooser), "user-langs"); + + async_id = cc_common_language_add_available_languages (GTK_LIST_STORE (model), regions, user_langs); + g_object_set_data_full (G_OBJECT (chooser), "language-async", GUINT_TO_POINTER (async_id), remove_async); + + parent = gtk_window_get_transient_for (GTK_WINDOW (chooser)); + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (parent)), NULL); + + g_object_set_data (G_OBJECT (chooser), "user-langs", NULL); + timeout = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (chooser), "timeout")); + g_object_weak_unref (G_OBJECT (chooser), (GWeakNotify) remove_timeout, GUINT_TO_POINTER (timeout)); + + /* And now listen for changes */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), chooser); + + return FALSE; +} + +static void +filter_clear (GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data) +{ + gtk_entry_set_text (entry, ""); +} + +static void +filter_changed (GtkWidget *entry, GParamSpec *pspec, GtkWidget *list) +{ + const gchar *pattern; + GtkTreeModel *filter_model; + GtkTreeModel *model; + + pattern = gtk_entry_get_text (GTK_ENTRY (entry)); + + filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); + + if (g_strcmp0 (pattern, "") == 0) { + g_object_set (G_OBJECT (entry), + "secondary-icon-name", "edit-find-symbolic", + "secondary-icon-activatable", FALSE, + "secondary-icon-sensitive", FALSE, + NULL); + + g_object_set_data_full (G_OBJECT (model), "filter-string", + g_strdup (""), g_free); + + } else { + g_object_set (G_OBJECT (entry), + "secondary-icon-name", "edit-clear-symbolic", + "secondary-icon-activatable", TRUE, + "secondary-icon-sensitive", TRUE, + NULL); + + g_object_set_data_full (G_OBJECT (model), "filter-string", + g_utf8_casefold (pattern, -1), g_free); + } + + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); +} + +static gboolean +filter_languages (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + const gchar *filter_string; + gchar *locale, *l; + gboolean visible; + + filter_string = g_object_get_data (G_OBJECT (model), "filter-string"); + + if (filter_string == NULL) { + return TRUE; + } + + gdk_threads_enter (); + gtk_tree_model_get (model, iter, DISPLAY_LOCALE_COL, &locale, -1); + gdk_threads_leave (); + + l = g_utf8_casefold (locale, -1); + + visible = strstr (l, filter_string) != NULL; + + g_free (locale); + g_free (l); + + return visible; +} + +GtkWidget * +cc_language_chooser_new (GtkWidget *parent, gboolean regions) +{ + GtkBuilder *builder; + const char *filename; + GError *error = NULL; + GtkWidget *chooser; + GtkWidget *list; + GtkWidget *button; + GtkWidget *entry; + GtkWidget *widget; + GHashTable *user_langs; + GdkCursor *cursor; + guint timeout; + GtkTreeModel *model; + GtkTreeModel *filter_model; + + builder = gtk_builder_new (); + filename = UIDIR "/language-chooser.ui"; + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + filename = "data/language-chooser.ui"; + if (!gtk_builder_add_from_file (builder, filename, &error)) { + g_warning ("failed to load language chooser: %s", error->message); + g_error_free (error); + return NULL; + } + + chooser = (GtkWidget *) gtk_builder_get_object (builder, "dialog"); + + if (regions) { + widget = (GtkWidget *) gtk_builder_get_object (builder, "title"); + gtk_label_set_text (GTK_LABEL (widget), _("Select a region")); + + /* communicate the preference to finish_language_chooser() */ + g_object_set_data (G_OBJECT (chooser), "regions", GINT_TO_POINTER (TRUE)); + } + + list = (GtkWidget *) gtk_builder_get_object (builder, "language-list"); + g_object_set_data (G_OBJECT (chooser), "list", list); + g_signal_connect (list, "row-activated", + G_CALLBACK (row_activated), chooser); + + button = (GtkWidget *) gtk_builder_get_object (builder, "ok-button"); + gtk_widget_grab_default (button); + + entry = (GtkWidget *) gtk_builder_get_object (builder, "filter-entry"); + g_object_set_data (G_OBJECT (chooser), "filter-entry", entry); + g_signal_connect (entry, "notify::text", + G_CALLBACK (filter_changed), list); + g_signal_connect (entry, "icon-release", + G_CALLBACK (filter_clear), NULL); + gtk_widget_grab_focus (entry); + + user_langs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + cc_common_language_setup_list (list, user_langs); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + filter_model = gtk_tree_model_filter_new (model, NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model), filter_languages, + NULL, NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (list), filter_model); + + /* Setup so that the list is added after the dialogue is shown */ + cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (gtk_widget_get_window (parent), cursor); + g_object_unref (cursor); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (parent)); + + g_object_set_data_full (G_OBJECT (chooser), "user-langs", + user_langs, (GDestroyNotify) g_hash_table_destroy); + timeout = g_idle_add ((GSourceFunc) finish_language_chooser, chooser); + g_object_set_data (G_OBJECT (chooser), "timeout", GUINT_TO_POINTER (timeout)); + g_object_weak_ref (G_OBJECT (chooser), (GWeakNotify) remove_timeout, GUINT_TO_POINTER (timeout)); + + g_object_unref (builder); + + return chooser; +} diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/gdm-languages.c gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/gdm-languages.c --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/gdm-languages.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/common/gdm-languages.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1326 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2008 Red Hat, Inc, + * 2007 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by : William Jon McCann + * Ray Strode + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gdm-languages.h" + +#include +#ifndef __LC_LAST +#define __LC_LAST 13 +#endif +#include "locarchive.h" + +#define ALIASES_FILE DATADIR "/gdm/locale.alias" +#define ARCHIVE_FILE LIBLOCALEDIR "/locale-archive" +#define SYSTEM_ARCHIVE_FILE "/usr/lib/locale/locale-archive" +#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes" +#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale" + +typedef struct _GdmLocale { + char *id; + char *name; + char *language_code; + char *territory_code; + char *codeset; + char *modifier; +} GdmLocale; + +static GHashTable *gdm_languages_map; +static GHashTable *gdm_territories_map; +static GHashTable *gdm_available_locales_map; +static GHashTable *gdm_language_count_map; +static GHashTable *gdm_territory_count_map; + +static char * construct_language_name (const char *language, + const char *territory, + const char *codeset, + const char *modifier); + +static gboolean language_name_is_valid (const char *language_name); + +static void +gdm_locale_free (GdmLocale *locale) +{ + if (locale == NULL) { + return; + } + + g_free (locale->id); + g_free (locale->name); + g_free (locale->codeset); + g_free (locale->modifier); + g_free (locale); +} + +static char * +normalize_codeset (const char *codeset) +{ + char *normalized_codeset; + const char *p; + char *q; + + normalized_codeset = g_strdup (codeset); + + if (codeset != NULL) { + for (p = codeset, q = normalized_codeset; + *p != '\0'; p++) { + + if (*p == '-' || *p == '_') { + continue; + } + + *q = g_ascii_tolower (*p); + q++; + } + *q = '\0'; + } + + return normalized_codeset; +} + +/* + * According to http://en.wikipedia.org/wiki/Locale + * locale names are of the form: + * [language[_territory][.codeset][@modifier]] + */ +gboolean +gdm_parse_language_name (const char *name, + char **language_codep, + char **territory_codep, + char **codesetp, + char **modifierp) +{ + GRegex *re; + GMatchInfo *match_info; + gboolean res; + GError *error; + gchar *normalized_codeset = NULL; + gchar *normalized_name = NULL; + gboolean retval; + + match_info = NULL; + retval = FALSE; + + error = NULL; + re = g_regex_new ("^(?P[^_.@[:space:]]+)" + "(_(?P[[:upper:]]+))?" + "(\\.(?P[-_0-9a-zA-Z]+))?" + "(@(?P[[:ascii:]]+))?$", + 0, 0, &error); + if (re == NULL) { + g_warning ("%s", error->message); + goto out; + } + + if (!g_regex_match (re, name, 0, &match_info) || + g_match_info_is_partial_match (match_info)) { + g_warning ("locale '%s' isn't valid\n", name); + goto out; + } + + res = g_match_info_matches (match_info); + if (! res) { + g_warning ("Unable to parse locale: %s", name); + goto out; + } + + retval = TRUE; + + if (language_codep != NULL) { + *language_codep = g_match_info_fetch_named (match_info, "language"); + } + + if (territory_codep != NULL) { + *territory_codep = g_match_info_fetch_named (match_info, "territory"); + + if (*territory_codep != NULL && + *territory_codep[0] == '\0') { + g_free (*territory_codep); + *territory_codep = NULL; + } + } + + if (codesetp != NULL) { + *codesetp = g_match_info_fetch_named (match_info, "codeset"); + + if (*codesetp != NULL && + *codesetp[0] == '\0') { + g_free (*codesetp); + *codesetp = NULL; + } + } + + if (modifierp != NULL) { + *modifierp = g_match_info_fetch_named (match_info, "modifier"); + + if (*modifierp != NULL && + *modifierp[0] == '\0') { + g_free (*modifierp); + *modifierp = NULL; + } + } + + if (codesetp != NULL && *codesetp != NULL) { + normalized_codeset = normalize_codeset (*codesetp); + normalized_name = construct_language_name (language_codep ? *language_codep : NULL, + territory_codep ? *territory_codep : NULL, + normalized_codeset, + modifierp ? *modifierp : NULL); + + if (language_name_is_valid (normalized_name)) { + g_free (*codesetp); + *codesetp = normalized_codeset; + } else { + g_free (normalized_codeset); + } + g_free (normalized_name); + } + + out: + g_match_info_free (match_info); + g_regex_unref (re); + + return retval; +} + +static char * +construct_language_name (const char *language, + const char *territory, + const char *codeset, + const char *modifier) +{ + char *name; + + g_assert (language[0] != 0); + g_assert (territory == NULL || territory[0] != 0); + g_assert (codeset == NULL || codeset[0] != 0); + g_assert (modifier == NULL || modifier[0] != 0); + + name = g_strdup_printf ("%s%s%s%s%s%s%s", + language, + territory != NULL? "_" : "", + territory != NULL? territory : "", + codeset != NULL? "." : "", + codeset != NULL? codeset : "", + modifier != NULL? "@" : "", + modifier != NULL? modifier : ""); + + return name; +} + +char * +gdm_normalize_language_name (const char *name) +{ + char *normalized_name; + char *language_code; + char *territory_code; + char *codeset; + char *modifier; + + if (name[0] == '\0') { + return NULL; + } + + gdm_parse_language_name (name, + &language_code, + &territory_code, + &codeset, &modifier); + + normalized_name = construct_language_name (language_code, + territory_code, + codeset, modifier); + g_free (language_code); + g_free (territory_code); + g_free (codeset); + g_free (modifier); + + return normalized_name; +} + +static gboolean +language_name_is_valid (const char *language_name) +{ + char *old_locale; + gboolean is_valid; +#ifdef WITH_INCOMPLETE_LOCALES + int lc_type_id = LC_CTYPE; +#else + int lc_type_id = LC_MESSAGES; +#endif + + old_locale = g_strdup (setlocale (lc_type_id, NULL)); + is_valid = setlocale (lc_type_id, language_name) != NULL; + setlocale (lc_type_id, old_locale); + g_free (old_locale); + + return is_valid; +} + +static void +language_name_get_codeset_details (const char *language_name, + char **pcodeset, + gboolean *is_utf8) +{ + char *old_locale; + char *codeset; + + old_locale = g_strdup (setlocale (LC_CTYPE, NULL)); + + if (setlocale (LC_CTYPE, language_name) == NULL) { + g_free (old_locale); + return; + } + + codeset = nl_langinfo (CODESET); + + if (pcodeset != NULL) { + *pcodeset = g_strdup (codeset); + } + + if (is_utf8 != NULL) { + codeset = normalize_codeset (codeset); + + *is_utf8 = strcmp (codeset, "utf8") == 0; + g_free (codeset); + } + + setlocale (LC_CTYPE, old_locale); + g_free (old_locale); +} + +gboolean +gdm_language_has_translations (const char *language_name) +{ + GDir *dir; + char *path; + const char *name; + gboolean has_translations; + + path = g_build_filename (GNOMELOCALEDIR, language_name, "LC_MESSAGES", NULL); + + has_translations = FALSE; + dir = g_dir_open (path, 0, NULL); + g_free (path); + + if (dir == NULL) { + goto out; + } + + do { + name = g_dir_read_name (dir); + + if (name == NULL) { + break; + } + + if (g_str_has_suffix (name, ".mo")) { + has_translations = TRUE; + break; + } + } while (name != NULL); + g_dir_close (dir); + +out: + return has_translations; +} + +static gboolean +add_locale (const char *language_name, + gboolean utf8_only) +{ + GdmLocale *locale; + GdmLocale *old_locale; + char *name; + gboolean is_utf8 = FALSE; + + g_return_val_if_fail (language_name != NULL, FALSE); + g_return_val_if_fail (*language_name != '\0', FALSE); + + language_name_get_codeset_details (language_name, NULL, &is_utf8); + + if (is_utf8) { + name = g_strdup (language_name); + } else if (utf8_only) { + name = g_strdup_printf ("%s.utf8", language_name); + + language_name_get_codeset_details (name, NULL, &is_utf8); + if (!is_utf8) { + g_free (name); + return FALSE; + } + } else { + name = g_strdup (language_name); + } + + if (!language_name_is_valid (name)) { + g_debug ("Ignoring '%s' as a locale, since it's invalid", name); + g_free (name); + return FALSE; + } + + locale = g_new0 (GdmLocale, 1); + gdm_parse_language_name (name, + &locale->language_code, + &locale->territory_code, + &locale->codeset, + &locale->modifier); + g_free (name); + name = NULL; + +#ifdef WITH_INCOMPLETE_LOCALES + if (utf8_only) { + if (locale->territory_code == NULL || locale->modifier) { + g_debug ("Ignoring '%s' as a locale, since it lacks territory code or modifier", name); + gdm_locale_free (locale); + return FALSE; + } + } +#endif + + locale->id = construct_language_name (locale->language_code, locale->territory_code, + NULL, locale->modifier); + locale->name = construct_language_name (locale->language_code, locale->territory_code, + locale->codeset, locale->modifier); + +#ifndef WITH_INCOMPLETE_LOCALES + if (!gdm_language_has_translations (locale->name) && + !gdm_language_has_translations (locale->id) && + !gdm_language_has_translations (locale->language_code) && + utf8_only) { + g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name); + gdm_locale_free (locale); + return FALSE; + } +#endif + + if (!utf8_only) { + g_free (locale->id); + locale->id = g_strdup (locale->name); + } + + old_locale = g_hash_table_lookup (gdm_available_locales_map, locale->id); + if (old_locale != NULL) { + if (strlen (old_locale->name) > strlen (locale->name)) { + gdm_locale_free (locale); + return FALSE; + } + } + + g_hash_table_insert (gdm_available_locales_map, g_strdup (locale->id), locale); + + return TRUE; +} + +struct nameent +{ + char *name; + uint32_t locrec_offset; +}; + +static gboolean +collect_locales_from_archive (void) +{ + GMappedFile *mapped; + GError *error; + char *addr; + struct locarhead *head; + struct namehashent *namehashtab; + struct nameent *names; + uint32_t used; + uint32_t cnt; + gsize len; + gboolean locales_collected; + + error = NULL; + mapped = g_mapped_file_new (ARCHIVE_FILE, FALSE, &error); + if (mapped == NULL) { + mapped = g_mapped_file_new (SYSTEM_ARCHIVE_FILE, FALSE, NULL); + if (mapped == NULL) { + g_warning ("Mapping failed for %s: %s", ARCHIVE_FILE, error->message); + g_error_free (error); + return FALSE; + } + g_error_free (error); + } + + locales_collected = FALSE; + + addr = g_mapped_file_get_contents (mapped); + len = g_mapped_file_get_length (mapped); + + head = (struct locarhead *) addr; + if (head->namehash_offset + head->namehash_size > len + || head->string_offset + head->string_size > len + || head->locrectab_offset + head->locrectab_size > len + || head->sumhash_offset + head->sumhash_size > len) { + goto out; + } + + namehashtab = (struct namehashent *) (addr + head->namehash_offset); + + names = (struct nameent *) g_new0 (struct nameent, head->namehash_used); + for (cnt = used = 0; cnt < head->namehash_size; ++cnt) { + if (namehashtab[cnt].locrec_offset != 0) { + names[used].name = addr + namehashtab[cnt].name_offset; + names[used++].locrec_offset = namehashtab[cnt].locrec_offset; + } + } + + for (cnt = 0; cnt < used; ++cnt) { + add_locale (names[cnt].name, TRUE); + } + + g_free (names); + + locales_collected = TRUE; + out: + + g_mapped_file_unref (mapped); + return locales_collected; +} + +static int +select_dirs (const struct dirent *dirent) +{ + int result = 0; + + if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) { + mode_t mode = 0; + +#ifdef _DIRENT_HAVE_D_TYPE + if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) { + mode = DTTOIF (dirent->d_type); + } else +#endif + { + struct stat st; + char *path; + + path = g_build_filename (LIBLOCALEDIR, dirent->d_name, NULL); + if (g_stat (path, &st) == 0) { + mode = st.st_mode; + } + g_free (path); + } + + result = S_ISDIR (mode); + } + + return result; +} + +static void +collect_locales_from_directory (void) +{ + struct dirent **dirents; + int ndirents; + int cnt; + + ndirents = scandir (LIBLOCALEDIR, &dirents, select_dirs, alphasort); + + for (cnt = 0; cnt < ndirents; ++cnt) { + add_locale (dirents[cnt]->d_name, TRUE); + } + + if (ndirents > 0) { + free (dirents); + } +} + +static void +collect_locales_from_locale_file (const char *locale_file) +{ + FILE *langlist; + char curline[256]; + char *getsret; + + if (locale_file == NULL) + return; + + langlist = fopen (locale_file, "r"); + + if (langlist == NULL) + return; + + for (;;) { + char *name; + char *lang; + char **lang_list; + int i; + + getsret = fgets (curline, sizeof (curline), langlist); + if (getsret == NULL) + break; + + if (curline[0] <= ' ' || + curline[0] == '#') + continue; + + name = strtok (curline, " \t\r\n"); + if (name == NULL) + continue; + + lang = strtok (NULL, " \t\r\n"); + if (lang == NULL) + continue; + + lang_list = g_strsplit (lang, ",", -1); + if (lang_list == NULL) + continue; + + lang = NULL; + for (i = 0; lang_list[i] != NULL; i++) { + if (add_locale (lang_list[i], FALSE)) { + break; + } + } + g_strfreev (lang_list); + } + + fclose (langlist); +} + +static void +count_languages_and_territories (void) +{ + gpointer value; + GHashTableIter iter; + + gdm_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + gdm_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + g_hash_table_iter_init (&iter, gdm_available_locales_map); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + GdmLocale *locale; + + locale = (GdmLocale *) value; + + if (locale->language_code != NULL) { + int count; + + count = GPOINTER_TO_INT (g_hash_table_lookup (gdm_language_count_map, locale->language_code)); + count++; + g_hash_table_insert (gdm_language_count_map, g_strdup (locale->language_code), GINT_TO_POINTER (count)); + } + + if (locale->territory_code != NULL) { + int count; + + count = GPOINTER_TO_INT (g_hash_table_lookup (gdm_territory_count_map, locale->territory_code)); + count++; + g_hash_table_insert (gdm_territory_count_map, g_strdup (locale->territory_code), GINT_TO_POINTER (count)); + } + } +} + +static void +collect_locales (void) +{ + + if (gdm_available_locales_map == NULL) { + gdm_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gdm_locale_free); + } + + if (!collect_locales_from_archive ()) { +#ifndef WITH_INCOMPLETE_LOCALES + g_warning ("Could not read list of available locales from libc, " + "guessing possible locales from available translations, " + "but list may be incomplete!"); +#endif + } + + collect_locales_from_directory (); + + collect_locales_from_locale_file (ALIASES_FILE); + + count_languages_and_territories (); +} + +static gint +get_language_count (const char *language) +{ + if (gdm_language_count_map == NULL) { + collect_locales (); + } + + return GPOINTER_TO_INT (g_hash_table_lookup (gdm_language_count_map, language)); +} + +static gboolean +is_unique_language (const char *language) +{ + return get_language_count (language) == 1; +} + +static gint +get_territory_count (const char *territory) +{ + if (gdm_territory_count_map == NULL) { + collect_locales (); + } + + return GPOINTER_TO_INT (g_hash_table_lookup (gdm_territory_count_map, territory)); +} + +static gboolean +is_unique_territory (const char *territory) +{ + return get_territory_count (territory) == 1; +} + +static gboolean +is_fallback_language (const char *code) +{ + const char *fallback_language_names[] = { "C", "POSIX", NULL }; + int i; + + for (i = 0; fallback_language_names[i] != NULL; i++) { + if (strcmp (code, fallback_language_names[i]) == 0) { + return TRUE; + } + } + + return FALSE; +} + +static const char * +get_language (const char *code) +{ + const char *name; + int len; + + g_assert (code != NULL); + + if (is_fallback_language (code)) { + return "Unspecified"; + } + + len = strlen (code); + if (len != 2 && len != 3) { + return NULL; + } + + name = (const char *) g_hash_table_lookup (gdm_languages_map, code); + + return name; +} + +static char * +get_first_item_in_semicolon_list (const char *list) +{ + char **items; + char *item; + + /* Some entries in iso codes have multiple values, separated + * by semicolons. Not really sure which one to pick, so + * we just arbitrarily pick the first one. + */ + items = g_strsplit (list, "; ", 2); + + item = g_strdup (items[0]); + g_strfreev (items); + + return item; +} + +static char * +get_translated_language (const char *code, + const char *locale) +{ + const char *language; + char *name; + + language = get_language (code); + + name = NULL; + if (language != NULL) { + const char *translated_name; + char *old_locale; + + if (locale != NULL) { + old_locale = g_strdup (setlocale (LC_MESSAGES, NULL)); + setlocale (LC_MESSAGES, locale); + } + + if (is_fallback_language (code)) { + name = g_strdup (_("Unspecified")); + } else { + translated_name = dgettext ("iso_639", language); + name = get_first_item_in_semicolon_list (translated_name); + } + + if (locale != NULL) { + setlocale (LC_MESSAGES, old_locale); + g_free (old_locale); + } + } + + return name; +} + +static const char * +get_territory (const char *code) +{ + const char *name; + int len; + + g_assert (code != NULL); + + len = strlen (code); + if (len != 2 && len != 3) { + return NULL; + } + + name = (const char *) g_hash_table_lookup (gdm_territories_map, code); + + return name; +} + +static char * +get_translated_territory (const char *code, + const char *locale) +{ + const char *territory; + char *name; + + territory = get_territory (code); + + name = NULL; + if (territory != NULL) { + const char *translated_territory; + char *old_locale; + + if (locale != NULL) { + old_locale = g_strdup (setlocale (LC_MESSAGES, NULL)); + setlocale (LC_MESSAGES, locale); + } + + translated_territory = dgettext ("iso_3166", territory); + name = get_first_item_in_semicolon_list (translated_territory); + + if (locale != NULL) { + setlocale (LC_MESSAGES, old_locale); + g_free (old_locale); + } + } + + return name; +} + +static void +languages_parse_start_tag (GMarkupParseContext *ctx, + const char *element_name, + const char **attr_names, + const char **attr_values, + gpointer user_data, + GError **error) +{ + const char *ccode_longB; + const char *ccode_longT; + const char *ccode; + const char *ccode_id; + const char *lang_name; + + if (! (g_str_equal (element_name, "iso_639_entry") || g_str_equal (element_name, "iso_639_3_entry")) + || attr_names == NULL || attr_values == NULL) { + return; + } + + ccode = NULL; + ccode_longB = NULL; + ccode_longT = NULL; + ccode_id = NULL; + lang_name = NULL; + + while (*attr_names && *attr_values) { + if (g_str_equal (*attr_names, "iso_639_1_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 2) { + return; + } + ccode = *attr_values; + } + } else if (g_str_equal (*attr_names, "iso_639_2B_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 3) { + return; + } + ccode_longB = *attr_values; + } + } else if (g_str_equal (*attr_names, "iso_639_2T_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 3) { + return; + } + ccode_longT = *attr_values; + } + } else if (g_str_equal (*attr_names, "id")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 2 && + strlen (*attr_values) != 3) { + return; + } + ccode_id = *attr_values; + } + } else if (g_str_equal (*attr_names, "name")) { + lang_name = *attr_values; + } + + ++attr_names; + ++attr_values; + } + + if (lang_name == NULL) { + return; + } + + if (ccode != NULL) { + g_hash_table_insert (gdm_languages_map, + g_strdup (ccode), + g_strdup (lang_name)); + } + if (ccode_longB != NULL) { + g_hash_table_insert (gdm_languages_map, + g_strdup (ccode_longB), + g_strdup (lang_name)); + } + if (ccode_longT != NULL) { + g_hash_table_insert (gdm_languages_map, + g_strdup (ccode_longT), + g_strdup (lang_name)); + } + if (ccode_id != NULL) { + g_hash_table_insert (gdm_languages_map, + g_strdup (ccode_id), + g_strdup (lang_name)); + } +} + +static void +territories_parse_start_tag (GMarkupParseContext *ctx, + const char *element_name, + const char **attr_names, + const char **attr_values, + gpointer user_data, + GError **error) +{ + const char *acode_2; + const char *acode_3; + const char *ncode; + const char *territory_common_name; + const char *territory_name; + + if (! g_str_equal (element_name, "iso_3166_entry") || attr_names == NULL || attr_values == NULL) { + return; + } + + acode_2 = NULL; + acode_3 = NULL; + ncode = NULL; + territory_common_name = NULL; + territory_name = NULL; + + while (*attr_names && *attr_values) { + if (g_str_equal (*attr_names, "alpha_2_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 2) { + return; + } + acode_2 = *attr_values; + } + } else if (g_str_equal (*attr_names, "alpha_3_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 3) { + return; + } + acode_3 = *attr_values; + } + } else if (g_str_equal (*attr_names, "numeric_code")) { + /* skip if empty */ + if (**attr_values) { + if (strlen (*attr_values) != 3) { + return; + } + ncode = *attr_values; + } + } else if (g_str_equal (*attr_names, "common_name")) { + /* skip if empty */ + if (**attr_values) { + territory_common_name = *attr_values; + } + } else if (g_str_equal (*attr_names, "name")) { + territory_name = *attr_values; + } + + ++attr_names; + ++attr_values; + } + + if (territory_common_name != NULL) { + territory_name = territory_common_name; + } + + if (territory_name == NULL) { + return; + } + + if (acode_2 != NULL) { + g_hash_table_insert (gdm_territories_map, + g_strdup (acode_2), + g_strdup (territory_name)); + } + if (acode_3 != NULL) { + g_hash_table_insert (gdm_territories_map, + g_strdup (acode_3), + g_strdup (territory_name)); + } + if (ncode != NULL) { + g_hash_table_insert (gdm_territories_map, + g_strdup (ncode), + g_strdup (territory_name)); + } +} + +static void +languages_variant_init (const char *variant) +{ + GError *error; + gboolean res; + char *buf; + gsize buf_len; + char *filename; + + bindtextdomain (variant, ISO_CODES_LOCALESDIR); + bind_textdomain_codeset (variant, "UTF-8"); + + error = NULL; + filename = g_strdup_printf (ISO_CODES_DATADIR "/%s.xml", variant); + res = g_file_get_contents (filename, + &buf, + &buf_len, + &error); + if (res) { + GMarkupParseContext *ctx; + GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL }; + + ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL); + + error = NULL; + res = g_markup_parse_context_parse (ctx, buf, buf_len, &error); + + if (! res) { + g_warning ("Failed to parse '%s': %s\n", + filename, + error->message); + g_error_free (error); + g_free (filename); + } + + g_markup_parse_context_free (ctx); + g_free (buf); + } else { + g_warning ("Failed to load '%s': %s\n", + filename, + error->message); + g_error_free (error); + } +} + +static void +languages_init (void) +{ + gdm_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + languages_variant_init ("iso_639"); + languages_variant_init ("iso_639_3"); +} + +static void +territories_init (void) +{ + GError *error; + gboolean res; + char *buf; + gsize buf_len; + + bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR); + bind_textdomain_codeset ("iso_3166", "UTF-8"); + + gdm_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + error = NULL; + res = g_file_get_contents (ISO_CODES_DATADIR "/iso_3166.xml", + &buf, + &buf_len, + &error); + if (res) { + GMarkupParseContext *ctx; + GMarkupParser parser = { territories_parse_start_tag, NULL, NULL, NULL, NULL }; + + ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL); + + error = NULL; + res = g_markup_parse_context_parse (ctx, buf, buf_len, &error); + + if (! res) { + g_warning ("Failed to parse '%s': %s\n", + ISO_CODES_DATADIR "/iso_3166.xml", + error->message); + g_error_free (error); + } + + g_markup_parse_context_free (ctx); + g_free (buf); + } else { + g_warning ("Failed to load '%s': %s\n", + ISO_CODES_DATADIR "/iso_3166.xml", + error->message); + g_error_free (error); + } +} + +char * +gdm_get_language_from_name (const char *name, + const char *locale) +{ + GString *full_language; + char *language_code; + char *territory_code; + char *codeset_code; + char *langinfo_codeset; + char *translated_language; + char *translated_territory; + gboolean is_utf8 = TRUE; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (*name != '\0', NULL); + + translated_territory = NULL; + translated_language = NULL; + langinfo_codeset = NULL; + + full_language = g_string_new (NULL); + + if (gdm_languages_map == NULL) { + languages_init (); + } + + if (gdm_territories_map == NULL) { + territories_init (); + } + + language_code = NULL; + territory_code = NULL; + codeset_code = NULL; + + gdm_parse_language_name (name, + &language_code, + &territory_code, + &codeset_code, + NULL); + + if (language_code == NULL) { + goto out; + } + + translated_language = get_translated_language (language_code, locale); + if (translated_language == NULL) { + goto out; + } + + full_language = g_string_append (full_language, translated_language); + + if (is_unique_language (language_code)) { + goto out; + } + + if (territory_code != NULL) { + translated_territory = get_translated_territory (territory_code, locale); + } + if (translated_territory != NULL) { + g_string_append_printf (full_language, + " (%s)", + translated_territory); + } + + language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); + + if (codeset_code == NULL && langinfo_codeset != NULL) { + codeset_code = g_strdup (langinfo_codeset); + } + + if (!is_utf8 && codeset_code) { + g_string_append_printf (full_language, + " [%s]", + codeset_code); + } + +out: + g_free (language_code); + g_free (territory_code); + g_free (codeset_code); + g_free (langinfo_codeset); + g_free (translated_language); + g_free (translated_territory); + + if (full_language->len == 0) { + g_string_free (full_language, TRUE); + return NULL; + } + + return g_string_free (full_language, FALSE); +} + +char * +gdm_get_region_from_name (const char *name, + const char *locale) +{ + GString *full_name; + char *language_code; + char *territory_code; + char *codeset_code; + char *langinfo_codeset; + char *translated_language; + char *translated_territory; + gboolean is_utf8 = TRUE; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (*name != '\0', NULL); + + translated_territory = NULL; + translated_language = NULL; + langinfo_codeset = NULL; + + full_name = g_string_new (NULL); + + if (gdm_languages_map == NULL) { + languages_init (); + } + + if (gdm_territories_map == NULL) { + territories_init (); + } + + language_code = NULL; + territory_code = NULL; + codeset_code = NULL; + + gdm_parse_language_name (name, + &language_code, + &territory_code, + &codeset_code, + NULL); + + if (territory_code == NULL) { + goto out; + } + + translated_territory = get_translated_territory (territory_code, locale); + g_string_append (full_name, translated_territory); + + if (is_unique_territory (territory_code)) { + goto out; + } + + if (language_code != NULL) { + translated_language = get_translated_language (language_code, locale); + } + if (translated_language != NULL) { + g_string_append_printf (full_name, + " (%s)", + translated_language); + } + + language_name_get_codeset_details (name, &langinfo_codeset, &is_utf8); + + if (codeset_code == NULL && langinfo_codeset != NULL) { + codeset_code = g_strdup (langinfo_codeset); + } + + if (!is_utf8 && codeset_code) { + g_string_append_printf (full_name, + " [%s]", + codeset_code); + } + +out: + g_free (language_code); + g_free (territory_code); + g_free (codeset_code); + g_free (langinfo_codeset); + g_free (translated_language); + g_free (translated_territory); + + if (full_name->len == 0) { + g_string_free (full_name, TRUE); + return NULL; + } + + return g_string_free (full_name, FALSE); +} + +char ** +gdm_get_all_language_names (void) +{ + GHashTableIter iter; + gpointer key, value; + GPtrArray *array; + + if (gdm_available_locales_map == NULL) { + collect_locales (); + } + + array = g_ptr_array_new (); + g_hash_table_iter_init (&iter, gdm_available_locales_map); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GdmLocale *locale; + + locale = (GdmLocale *) value; + + g_ptr_array_add (array, g_strdup (locale->name)); + } + g_ptr_array_add (array, NULL); + + return (char **) g_ptr_array_free (array, FALSE); +} diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-formats.c gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-formats.c --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-formats.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-formats.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2011 Rodrigo Moya + * + * Written by: Rodrigo Moya + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "cc-common-language.h" +#include "cc-language-chooser.h" +#include "gdm-languages.h" +#include "gnome-region-panel-formats.h" + +static void +display_date (GtkLabel *label, GDateTime *dt, const gchar *format) +{ + gchar *s; + + s = g_date_time_format (dt, format); + s = g_strstrip (s); + gtk_label_set_text (label, s); + g_free (s); +} + +static void +select_region (GtkTreeView *treeview, const gchar *lang) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreePath *path; + gboolean cont; + + model = gtk_tree_view_get_model (treeview); + selection = gtk_tree_view_get_selection (treeview); + cont = gtk_tree_model_get_iter_first (model, &iter); + while (cont) { + gchar *locale; + + gtk_tree_model_get (model, &iter, 0, &locale, -1); + if (g_strcmp0 (locale, lang) == 0) { + gtk_tree_selection_select_iter (selection, &iter); + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + g_free (locale); + break; + } + g_free (locale); + + cont = gtk_tree_model_iter_next (model, &iter); + } +} + +static void +update_examples_cb (GtkTreeSelection *selection, gpointer user_data) +{ + GtkBuilder *builder = GTK_BUILDER (user_data); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *active_id; + gchar *locale; + GDateTime *dt; + gchar *s; + struct lconv *num_info; + const char *fmt; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + gtk_tree_model_get (model, &iter, 0, &active_id, -1); + + locale = g_strdup (setlocale (LC_TIME, NULL)); + setlocale (LC_TIME, active_id); + + dt = g_date_time_new_now_local (); + + /* Display dates */ + display_date (GTK_LABEL (gtk_builder_get_object (builder, "full_date_format")), dt, "%A %e %B %Y"); + display_date (GTK_LABEL (gtk_builder_get_object (builder, "full_day_format")), dt, "%e %B %Y"); + display_date (GTK_LABEL (gtk_builder_get_object (builder, "short_day_format")), dt, "%e %b %Y"); + display_date (GTK_LABEL (gtk_builder_get_object (builder, "shortest_day_format")), dt, "%x"); + + /* Display times */ + display_date (GTK_LABEL (gtk_builder_get_object (builder, "full_time_format")), dt, "%r %Z"); + display_date (GTK_LABEL (gtk_builder_get_object (builder, "short_time_format")), dt, "%X"); + + setlocale (LC_TIME, locale); + g_free (locale); + + /* Display numbers */ + locale = g_strdup (setlocale (LC_NUMERIC, NULL)); + setlocale (LC_NUMERIC, active_id); + + s = g_strdup_printf ("%'.2f", 123456789.00); + gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "numbers_format")), s); + g_free (s); + + setlocale (LC_NUMERIC, locale); + g_free (locale); + + /* Display currency */ + locale = g_strdup (setlocale (LC_MONETARY, NULL)); + setlocale (LC_MONETARY, active_id); + + num_info = localeconv (); + if (num_info != NULL) { + gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "currency_format")), num_info->currency_symbol); + } + + setlocale (LC_MONETARY, locale); + g_free (locale); + + /* Display measurement */ +#ifdef LC_MEASUREMENT + locale = g_strdup (setlocale (LC_MEASUREMENT, NULL)); + setlocale (LC_MEASUREMENT, active_id); + + fmt = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT); + if (fmt && *fmt == 2) + gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "measurement_format")), _("Imperial")); + else + gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "measurement_format")), _("Metric")); + + setlocale (LC_MEASUREMENT, locale); + g_free (locale); +#endif + g_free (active_id); +} + + +static void +update_settings_cb (GtkTreeSelection *selection, gpointer user_data) +{ + GtkBuilder *builder = GTK_BUILDER (user_data); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *active_id; + GtkWidget *treeview; + GSettings *locale_settings; + gchar *current_setting; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + gtk_tree_model_get (model, &iter, 0, &active_id, -1); + + treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector")); + + locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); + current_setting = g_settings_get_string (locale_settings, "region"); + + if (g_strcmp0 (active_id, current_setting) != 0) { + g_settings_set_string (locale_settings, "region", active_id); + } + + g_free (current_setting); + g_free (active_id); +} + +static void +setting_changed_cb (GSettings *locale_settings, gchar *key, GtkTreeView *treeview) +{ + gchar *current_setting; + + current_setting = g_settings_get_string (locale_settings, "region"); + select_region (treeview, current_setting); + g_free (current_setting); +} + +static gint +sort_regions (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) +{ + gchar *la, *lb; + gint result; + + gtk_tree_model_get (model, a, 1, &la, -1); + gtk_tree_model_get (model, b, 1, &lb, -1); + + result = strcmp (la, lb); + + g_free (la); + g_free (lb); + + return result; +} + +static void +populate_regions (GtkBuilder *builder, const gchar *current_lang) +{ + gchar *current_region; + GSettings *locale_settings; + GHashTable *ht; + GHashTableIter htiter; + GtkTreeModel *model; + gchar *name, *language; + GtkWidget *treeview; + GtkTreeIter iter; + GtkTreeSelection *selection; + + treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector")); + /* don't update the setting just because the list is repopulated */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_handlers_block_by_func (selection, update_settings_cb, builder); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); + locale_settings = g_object_get_data (G_OBJECT (treeview), "settings"); + + ht = cc_common_language_get_initial_regions (current_lang); + + current_region = g_settings_get_string (locale_settings, "region"); + if (!current_region || !current_region[0]) { + current_region = g_strdup (current_lang); + } + else if (!g_hash_table_lookup (ht, current_region)) { + name = gdm_get_region_from_name (current_region, NULL); + g_hash_table_insert (ht, g_strdup (current_region), name); + } + + gtk_list_store_clear (GTK_LIST_STORE (model)); + + g_hash_table_iter_init (&htiter, ht); + while (g_hash_table_iter_next (&htiter, (gpointer *)&name, (gpointer *)&language)) { + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, name, 1, language, -1); + } + g_hash_table_unref (ht); + + select_region (GTK_TREE_VIEW (treeview), current_region); + + g_free (current_region); + + g_signal_handlers_unblock_by_func (selection, update_settings_cb, builder); +} + +static void +region_response (GtkDialog *dialog, + gint response_id, + GtkWidget *treeview) +{ + gchar *lang; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + gtk_widget_hide (GTK_WIDGET (dialog)); + + if (response_id != GTK_RESPONSE_OK) { + return; + } + + lang = cc_language_chooser_get_language (GTK_WIDGET (dialog)); + + if (lang == NULL) { + return; + } + model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + if (cc_common_language_get_iter_for_region (model, lang, &iter)) { + gtk_tree_selection_select_iter (selection, &iter); + } + + gtk_widget_grab_focus (treeview); + + g_free (lang); +} + +static void +add_region (GtkWidget *button, GtkWidget *treeview) +{ + GtkWidget *toplevel; + GtkWidget *chooser; + + toplevel = gtk_widget_get_toplevel (button); + chooser = g_object_get_data (G_OBJECT (button), "chooser"); + if (chooser == NULL) { + chooser = cc_language_chooser_new (toplevel, TRUE); + + g_signal_connect (chooser, "response", + G_CALLBACK (region_response), treeview); + g_signal_connect (chooser, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + g_object_set_data_full (G_OBJECT (button), "chooser", + chooser, (GDestroyNotify)gtk_widget_destroy); + } + else { + cc_language_chooser_clear_filter (chooser); + } + + gdk_window_set_cursor (gtk_widget_get_window (toplevel), NULL); + gtk_window_present (GTK_WINDOW (chooser)); +} + +void +setup_formats (GtkBuilder *builder) +{ + GtkWidget *treeview; + gchar *current_lang; + GtkTreeModel *model; + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + GtkWidget *widget; + GtkStyleContext *context; + GSettings *locale_settings; + GtkTreeSelection *selection; + + locale_settings = g_settings_new ("org.gnome.system.locale"); + + /* Setup junction between toolbar and treeview */ + widget = (GtkWidget *)gtk_builder_get_object (builder, "region-swindow"); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + widget = (GtkWidget *)gtk_builder_get_object (builder, "region-toolbar"); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + /* Setup formats selector */ + treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector")); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "width-chars", 40, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes (NULL, cell, "text", 1, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + model = (GtkTreeModel*)gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), + sort_regions, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model); + + g_object_set_data_full (G_OBJECT (treeview), "settings", locale_settings, g_object_unref); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect (selection, "changed", + G_CALLBACK (update_settings_cb), builder); + g_signal_connect (selection, "changed", + G_CALLBACK (update_examples_cb), builder); + + /* Connect buttons */ + widget = (GtkWidget *)gtk_builder_get_object (builder, "region_add"); + g_signal_connect (widget, "clicked", + G_CALLBACK (add_region), treeview); + + current_lang = cc_common_language_get_current_language (); + populate_regions (builder, current_lang); + g_free (current_lang); + + g_signal_connect (locale_settings, "changed::region", + G_CALLBACK (setting_changed_cb), treeview); +} + +void +formats_update_language (GtkBuilder *builder, + const gchar *language) +{ + populate_regions (builder, language); +} + diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.c gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.c --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2011 Rodrigo Moya + * + * Written by: Rodrigo Moya + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#include "cc-common-language.h" +#include "gdm-languages.h" +#include "gnome-region-panel-system.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (dialog, s)) + +static GSettings *locale_settings, *input_sources_settings; +static GDBusProxy *localed_proxy; +static GPermission *localed_permission; + +static void +update_copy_button (GtkBuilder *dialog) +{ + GtkWidget *label; + GtkWidget *button; + const gchar *user_lang, *system_lang; + const gchar *user_region, *system_region; + const gchar *user_input_source, *system_input_source; + const gchar *user_input_variants, *system_input_variants; + gboolean layouts_differ; + + label = WID ("user_display_language"); + user_lang = g_object_get_data (G_OBJECT (label), "language"); + + label = WID ("system_display_language"); + system_lang = g_object_get_data (G_OBJECT (label), "language"); + + label = WID ("user_format"); + user_region = g_object_get_data (G_OBJECT (label), "region"); + + label = WID ("system_format"); + system_region = g_object_get_data (G_OBJECT (label), "region"); + + label = WID ("user_input_source"); + user_input_source = g_object_get_data (G_OBJECT (label), "input_source"); + user_input_variants = g_object_get_data (G_OBJECT (label), "input_variants"); + + label = WID ("system_input_source"); + system_input_source = g_object_get_data (G_OBJECT (label), "input_source"); + system_input_variants = g_object_get_data (G_OBJECT (label), "input_variants"); + + button = WID ("copy_settings_button"); + + if (user_input_source && user_input_source[0]) { + layouts_differ = (g_strcmp0 (user_input_source, system_input_source) != 0); + if (layouts_differ == FALSE) + layouts_differ = (g_strcmp0 (user_input_variants, system_input_variants) != 0); + } else { + /* Nothing to copy */ + layouts_differ = FALSE; + } + + if (g_strcmp0 (user_lang, system_lang) == 0 && + g_strcmp0 (user_region, system_region) == 0 && + !layouts_differ) + gtk_widget_set_sensitive (button, FALSE); + else + gtk_widget_set_sensitive (button, TRUE); +} + +static void +locale_settings_changed (GSettings *settings, + const gchar *key, + GtkBuilder *dialog) +{ + GtkWidget *label; + gchar *region, *display_region; + + region = g_settings_get_string (locale_settings, "region"); + if (!region || !region[0]) { + label = WID ("user_display_language"); + region = g_strdup ((gchar*)g_object_get_data (G_OBJECT (label), "language")); + } + + display_region = gdm_get_region_from_name (region, NULL); + label = WID ("user_format"); + gtk_label_set_text (GTK_LABEL (label), display_region); + g_object_set_data_full (G_OBJECT (label), "region", g_strdup (region), g_free); + g_free (region); + g_free (display_region); + + update_copy_button (dialog); +} + +void +system_update_language (GtkBuilder *dialog, const gchar *language) +{ + gchar *display_language; + GtkWidget *label; + + display_language = gdm_get_language_from_name (language, NULL); + label = WID ("user_display_language"); + gtk_label_set_text (GTK_LABEL (label), display_language); + g_object_set_data_full (G_OBJECT (label), "language", g_strdup (language), g_free); + g_free (display_language); + + /* need to update the region display in case the setting is '' */ + locale_settings_changed (locale_settings, "region", dialog); + + update_copy_button (dialog); +} + +static void +input_sources_changed (GSettings *settings, + const gchar *key, + GtkBuilder *dialog) +{ + GString *disp, *list, *variants; + GtkWidget *label; + GnomeXkbInfo *xkb_info; + GVariantIter iter; + GVariant *sources; + const gchar *type; + const gchar *id; + + sources = g_settings_get_value (input_sources_settings, "sources"); + xkb_info = gnome_xkb_info_new (); + + label = WID ("user_input_source"); + disp = g_string_new (""); + list = g_string_new (""); + variants = g_string_new (""); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) { + /* We can't copy non-XKB layouts to the system yet */ + if (g_str_equal (type, "xkb")) { + char **split; + gchar *layout, *variant; + const char *name; + + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (disp->str[0] != '\0') + g_string_append (disp, ", "); + g_string_append (disp, name); + + split = g_strsplit (id, "+", 2); + + if (split == NULL || split[0] == NULL) + continue; + + layout = split[0]; + variant = split[1]; + + if (list->str[0] != '\0') { + g_string_append (list, ","); + g_string_append (variants, ","); + } + g_string_append (list, layout); + g_string_append (variants, variant ? variant : ""); + + g_strfreev (split); + } + } + g_variant_unref (sources); + g_object_unref (xkb_info); + + g_object_set_data_full (G_OBJECT (label), "input_source", g_string_free (list, FALSE), g_free); + g_object_set_data_full (G_OBJECT (label), "input_variants", g_string_free (variants, FALSE), g_free); + + gtk_label_set_text (GTK_LABEL (label), disp->str); + g_string_free (disp, TRUE); + + update_copy_button (dialog); +} + +static void +update_property (GDBusProxy *proxy, + const char *property) +{ + GError *error = NULL; + GVariant *variant; + + /* Work around systemd-localed not sending us back + * the property value when changing values */ + variant = g_dbus_proxy_call_sync (proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", "org.freedesktop.locale1", property), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) { + g_warning ("Failed to get property '%s': %s", property, error->message); + g_error_free (error); + } else { + GVariant *v; + + g_variant_get (variant, "(v)", &v); + g_dbus_proxy_set_cached_property (proxy, property, v); + g_variant_unref (variant); + } +} + +static void +on_localed_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + const gchar **invalidated_properties, + GtkBuilder *dialog) +{ + GVariant *v, *w; + GtkWidget *label; + GnomeXkbInfo *xkb_info; + char **layouts; + char **variants; + GString *disp; + guint i, n; + + if (invalidated_properties != NULL) { + guint i; + for (i = 0; invalidated_properties[i] != NULL; i++) { + if (g_str_equal (invalidated_properties[i], "Locale")) + update_property (proxy, "Locale"); + else if (g_str_equal (invalidated_properties[i], "X11Layout")) + update_property (proxy, "X11Layout"); + else if (g_str_equal (invalidated_properties[i], "X11Variant")) + update_property (proxy, "X11Variant"); + } + } + + v = g_dbus_proxy_get_cached_property (proxy, "Locale"); + if (v) { + const gchar **strv; + gsize len; + gint i; + const gchar *lang, *messages, *time; + gchar *name; + GtkWidget *label; + + strv = g_variant_get_strv (v, &len); + + lang = messages = time = NULL; + for (i = 0; strv[i]; i++) { + if (g_str_has_prefix (strv[i], "LANG=")) { + lang = strv[i] + strlen ("LANG="); + } + else if (g_str_has_prefix (strv[i], "LC_MESSAGES=")) { + messages = strv[i] + strlen ("LC_MESSAGES="); + } + else if (g_str_has_prefix (strv[i], "LC_TIME=")) { + time = strv[i] + strlen ("LC_TIME="); + } + } + if (!messages) { + messages = lang; + } + if (!time) { + time = lang; + } + + if (messages) { + name = gdm_get_language_from_name (messages, NULL); + label = WID ("system_display_language"); + gtk_label_set_text (GTK_LABEL (label), name); + g_free (name); + g_object_set_data_full (G_OBJECT (label), "language", g_strdup (lang), g_free); + } + + if (time) { + name = gdm_get_region_from_name (time, NULL); + label = WID ("system_format"); + gtk_label_set_text (GTK_LABEL (label), name); + g_free (name); + g_object_set_data_full (G_OBJECT (label), "region", g_strdup (time), g_free); + } + g_variant_unref (v); + } + + label = WID ("system_input_source"); + v = g_dbus_proxy_get_cached_property (proxy, "X11Layout"); + if (v) { + layouts = g_strsplit (g_variant_get_string (v, NULL), ",", -1); + g_object_set_data_full (G_OBJECT (label), "input_source", + g_variant_dup_string (v, NULL), g_free); + g_variant_unref (v); + } else { + g_object_set_data_full (G_OBJECT (label), "input_source", NULL, g_free); + update_copy_button (dialog); + return; + } + + variants = NULL; + g_object_set_data_full (G_OBJECT (label), "input_variants", NULL, g_free); + + w = g_dbus_proxy_get_cached_property (proxy, "X11Variant"); + if (w) { + const char *variants_str; + + variants_str = g_variant_get_string (w, NULL); + g_debug ("Got variants '%s'", variants_str); + if (variants_str && *variants_str != '\0') { + variants = g_strsplit (variants_str, ",", -1); + g_object_set_data_full (G_OBJECT (label), "input_variants", + g_strdup (variants_str), g_free); + } + g_variant_unref (w); + } + + if (variants && variants[0]) + n = MIN (g_strv_length (layouts), g_strv_length (variants)); + else + n = g_strv_length (layouts); + + xkb_info = gnome_xkb_info_new (); + disp = g_string_new (""); + for (i = 0; i < n && layouts[i][0]; i++) { + const char *name; + char *id; + + if (variants && variants[i] && variants[i][0]) + id = g_strdup_printf ("%s+%s", layouts[i], variants[i]); + else + id = g_strdup (layouts[i]); + + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (disp->str[0] != '\0') + disp = g_string_append (disp, ", "); + disp = g_string_append (disp, name ? name : id); + + g_free (id); + } + gtk_label_set_text (GTK_LABEL (label), disp->str); + g_string_free (disp, TRUE); + + g_strfreev (variants); + g_strfreev (layouts); + g_object_unref (xkb_info); + + update_copy_button (dialog); +} + +static void +localed_proxy_ready (GObject *source, + GAsyncResult *res, + GtkBuilder *dialog) +{ + GError *error = NULL; + + localed_proxy = g_dbus_proxy_new_finish (res, &error); + + if (!localed_proxy) { + g_warning ("Failed to contact localed: %s\n", error->message); + g_error_free (error); + return; + } + + g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, localed_proxy); + + g_signal_connect (localed_proxy, "g-properties-changed", + G_CALLBACK (on_localed_properties_changed), dialog); + + on_localed_properties_changed (localed_proxy, NULL, NULL, dialog); +} + +static void +copy_settings (GtkButton *button, GtkBuilder *dialog) +{ + const gchar *language; + const gchar *region; + const gchar *layout; + const gchar *variants; + GtkWidget *label; + GVariantBuilder *b; + gchar *s; + + label = WID ("user_display_language"); + language = g_object_get_data (G_OBJECT (label), "language"); + label = WID ("user_format"); + region = g_object_get_data (G_OBJECT (label), "region"); + + b = g_variant_builder_new (G_VARIANT_TYPE ("as")); + s = g_strconcat ("LANG=", language, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + if (g_strcmp0 (language, region) != 0) { + s = g_strconcat ("LC_TIME=", region, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + s = g_strconcat ("LC_NUMERIC=", region, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + s = g_strconcat ("LC_MONETARY=", region, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + s = g_strconcat ("LC_MEASUREMENT=", region, NULL); + g_variant_builder_add (b, "s", s); + g_free (s); + } + + g_dbus_proxy_call (localed_proxy, + "SetLocale", + g_variant_new ("(asb)", b, TRUE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); + g_variant_builder_unref (b); + + label = WID ("user_input_source"); + layout = g_object_get_data (G_OBJECT (label), "input_source"); + variants = g_object_get_data (G_OBJECT (label), "input_variants"); + + if (layout == NULL || layout[0] == '\0') { + g_debug ("Not calling SetX11Keyboard, as there are no XKB input sources in the user's settings"); + return; + } + + g_dbus_proxy_call (localed_proxy, + "SetX11Keyboard", + g_variant_new ("(ssssbb)", layout, "", variants ? variants : "", "", TRUE, TRUE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); +} + +static void +on_permission_changed (GPermission *permission, + GParamSpec *pspec, + GtkBuilder *dialog) +{ + GtkWidget *button; + GtkWidget *label; + gboolean can_acquire; + gboolean allowed; + + if (permission) { + can_acquire = g_permission_get_can_acquire (permission); + allowed = g_permission_get_allowed (permission); + } + else { + can_acquire = FALSE; + allowed = FALSE; + } + + button = WID ("copy_settings_button"); + label = WID ("system-title"); + + if (!allowed && !can_acquire) { + gtk_label_set_text (GTK_LABEL (label), + _("The login screen, system accounts and new user accounts use the system-wide Region and Language settings.")); + gtk_widget_hide (button); + } + else { + gtk_label_set_text (GTK_LABEL (label), + _("The login screen, system accounts and new user accounts use the system-wide Region and Language settings. You may change the system settings to match yours.")); + gtk_widget_show (button); + if (allowed) { + gtk_button_set_label (GTK_BUTTON (button), _("Copy Settings")); + } + else { + gtk_button_set_label (GTK_BUTTON (button), _("Copy Settings...")); + } + } +} + +void +setup_system (GtkBuilder *dialog) +{ + gchar *language; + GDBusConnection *bus; + GtkWidget *button; + + localed_permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-locale", NULL, NULL, NULL); + if (localed_permission == NULL) { + GtkWidget *tab_widget, *notebook; + int num; + + tab_widget = WID ("table3"); + notebook = WID ("region_notebook"); + num = gtk_notebook_page_num (GTK_NOTEBOOK (notebook), tab_widget); + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), num); + return; + } + + g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, localed_permission); + g_signal_connect (localed_permission, "notify", + G_CALLBACK (on_permission_changed), dialog); + on_permission_changed (localed_permission, NULL, dialog); + + + button = WID ("copy_settings_button"); + g_signal_connect (button, "clicked", + G_CALLBACK (copy_settings), dialog); + + + locale_settings = g_settings_new ("org.gnome.system.locale"); + g_signal_connect (locale_settings, "changed::region", + G_CALLBACK (locale_settings_changed), dialog); + g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, locale_settings); + + input_sources_settings = g_settings_new ("org.gnome.desktop.input-sources"); + g_signal_connect (input_sources_settings, "changed::sources", + G_CALLBACK (input_sources_changed), dialog); + g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, input_sources_settings); + + /* Display user settings */ + language = cc_common_language_get_current_language (); + system_update_language (dialog, language); + g_free (language); + + locale_settings_changed (locale_settings, "region", dialog); + + input_sources_changed (input_sources_settings, "sources", dialog); + + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); + g_dbus_proxy_new (bus, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + NULL, + (GAsyncReadyCallback) localed_proxy_ready, + dialog); + g_object_unref (bus); +} diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.h gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.h --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.h 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel-system.h 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 Rodrigo Moya + * + * Written by: Rodrigo Moya + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __GNOME_REGION_PANEL_SYSTEM_H +#define __GNOME_REGION_PANEL_SYSTEM_H + +#include + +void setup_system (GtkBuilder *builder); +void system_update_language (GtkBuilder *builder, + const gchar *language); + +#endif diff -Nru gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel.ui gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel.ui --- gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/52_region_language.patch/panels/region/gnome-region-panel.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1352 @@ + + + + + 100 + 2000 + 500 + 10 + 10 + + + 1 + 100000 + 1 + 1 + 10 + + + 10 + 110 + 30 + 10 + 10 + + + 100 + 2500 + 1000 + 200 + 200 + + + 500 + 0.5 + 10 + 10 + + + 900 + 0.5 + 10 + 10 + + + 3000 + 1800 + 10 + 10 + + + 10 + 1000 + 300 + 10 + 10 + + + 10 + 2000 + 300 + 10 + 10 + + + 1 + 100000 + 1 + 1 + 10 + + + + False + 5 + Region and Language + 600 + 430 + dialog + + + True + False + vertical + 2 + + + False + + + False + True + end + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 12 + + + True + True + 10 + + + True + False + 12 + 12 + + + True + False + 0 + Select a display language (change will be applied next time you log in) + + + False + True + 0 + + + + + True + False + vertical + + + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + True + False + icons + False + 1 + + + + + False + True + Add Language + False + True + list-add-symbolic + + + False + True + + + + + False + True + 1 + + + + + False + + + True + False + True + Add Language + + + True + True + 0 + + + + + Install languages... + True + True + True + True + + + False + True + 1 + + + + + False + True + 1 + + + + + True + True + 1 + + + + + + + True + False + Language + + + False + + + + + True + False + 12 + 12 + 12 + 12 + 6 + 12 + + + True + False + start + Select a region (change will be applied the next time you log in) + + + 0 + 0 + 2 + 1 + + + + + True + False + vertical + + + True + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + icons + False + 1 + True + + + + False + Add Region + True + False + True + list-add-symbolic + + + False + True + + + + + False + True + Remove Region + False + False + True + list-remove-symbolic + + + False + True + + + + + False + True + 1 + + + + + 0 + 1 + 1 + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 9 + 2 + + + True + False + 0 + Dates + + + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 3 + 4 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Times + + + 4 + 5 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 4 + 5 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 5 + 6 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Numbers + + + 6 + 7 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 6 + 7 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Currency + + + 7 + 8 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 7 + 8 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Measurement + + + 8 + 9 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 8 + 9 + GTK_FILL + 3 + 3 + + + + + + + + + True + False + Examples + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + + + 1 + + + + + True + False + Formats + + + 1 + False + + + + + True + False + 12 + 12 + + + True + False + 0 + Select keyboards or other input sources + + + False + False + 0 + + + + + True + False + 12 + + + True + False + + + True + True + in + + + True + True + False + + + + + True + True + 0 + + + + + True + False + icons + False + 1 + + + + True + + + True + + + True + + + Add Input Source + + + + + + True + list-add-symbolic + 1 + + + + + + + True + + + Remove Input Source + + + + + True + list-remove-symbolic + 1 + + + + + + + + + + + + True + False + + + True + + + + + + True + + + True + + + True + + + Move Input Source Up + + + + + + True + go-up-symbolic + 1 + + + + + + + True + + + Move Input Source Down + + + + + True + go-down-symbolic + 1 + + + + + + + + + + + + True + False + True + + + True + + + + + + True + + + True + + + True + + + Input Source Settings + + + + + + True + preferences-system-symbolic + 1 + 16 + + + + + + + True + + + Show Keyboard Layout + + + + + + True + input-keyboard-symbolic + 1 + + + + + + + + + + + + False + True + 1 + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 6 + 6 + 6 + + + True + False + 0 + Switch to previous source + + + 0 + 0 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Space + + + + 1 + 0 + 1 + 1 + + + + + True + False + 0 + Switch to next source + + + 0 + 1 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Shift+Space + + + + 1 + 1 + 1 + 1 + + + + + True + True + Shortcut Settings + end + + + 1 + 2 + 1 + 1 + + + + + + + + + True + False + Shortcuts + True + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + 3 + + + + + True + False + Input Sources + + + 3 + False + + + + + True + False + 3 + 2 + 12 + 12 + + + True + False + 0 + 6 + 6 + The login screen, system accounts and new user accounts use the system-wide Region and Language settings. You may change the system settings to match yours. + True + 60 + + + 2 + GTK_FILL + GTK_SHRINK + 3 + 3 + + + + + True + False + 0 + none + + + True + False + 12 + 12 + 3 + 2 + 3 + 3 + + + True + False + 0 + Display language: + + + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + 0 + Input source: + + + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + 0 + True + 18 + + + 1 + 2 + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + Format: + + + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + + + True + False + Your settings + + + + + + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + none + + + True + False + 12 + 12 + 3 + 2 + 3 + 3 + + + True + False + 0 + Display language: + + + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + 0 + Input source: + + + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + 0 + True + 18 + + + 1 + 2 + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + Format: + + + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + + + True + False + System settings + + + + + + + + 1 + 2 + 1 + 2 + GTK_FILL + 3 + 3 + + + + + Copy Settings... + False + True + True + True + + + 1 + 2 + 2 + 3 + GTK_SHRINK + GTK_SHRINK + 3 + 3 + + + + + + + + 4 + + + + + True + False + System + + + 4 + False + + + + + False + False + 0 + + + + + False + True + 1 + + + + + + + vertical + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/bluetooth/cc-bluetooth-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/bluetooth/cc-bluetooth-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/bluetooth/cc-bluetooth-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/bluetooth/cc-bluetooth-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,923 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2006-2010 Bastien Nocera + * + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "cc-bluetooth-panel.h" + +#include +#include +#include +#include +#include + +CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel) + +#define BLUETOOTH_PANEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_BLUETOOTH_PANEL, CcBluetoothPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +#define KEYBOARD_PREFS "keyboard" +#define MOUSE_PREFS "mouse" +#define SOUND_PREFS "sound" +#define WIZARD "bluetooth-wizard" + +struct CcBluetoothPanelPrivate { + GtkBuilder *builder; + GtkWidget *chooser; + char *selected_bdaddr; + BluetoothClient *client; + BluetoothKillswitch *killswitch; + gboolean debug; + GHashTable *connecting_devices; +}; + +static void cc_bluetooth_panel_finalize (GObject *object); + +static void +launch_command (const char *command) +{ + GError *error = NULL; + + if (!g_spawn_command_line_async(command, &error)) { + g_warning ("Couldn't execute command '%s': %s\n", command, error->message); + g_error_free (error); + } +} + +static const char * +cc_bluetooth_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/bluetooth"; +} + +static void +cc_bluetooth_panel_class_init (CcBluetoothPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + object_class->finalize = cc_bluetooth_panel_finalize; + + panel_class->get_help_uri = cc_bluetooth_panel_get_help_uri; + + g_type_class_add_private (klass, sizeof (CcBluetoothPanelPrivate)); +} + +static void +cc_bluetooth_panel_finalize (GObject *object) +{ + CcBluetoothPanel *self; + + bluetooth_plugin_manager_cleanup (); + + self = CC_BLUETOOTH_PANEL (object); + g_clear_object (&self->priv->builder); + g_clear_object (&self->priv->killswitch); + g_clear_object (&self->priv->client); + + g_clear_pointer (&self->priv->connecting_devices, g_hash_table_destroy); + g_clear_pointer (&self->priv->selected_bdaddr, g_free); + + G_OBJECT_CLASS (cc_bluetooth_panel_parent_class)->finalize (object); +} + +enum { + CONNECTING_NOTEBOOK_PAGE_SWITCH = 0, + CONNECTING_NOTEBOOK_PAGE_SPINNER = 1 +}; + +static void +set_connecting_page (CcBluetoothPanel *self, + int page) +{ + if (page == CONNECTING_NOTEBOOK_PAGE_SPINNER) + gtk_spinner_start (GTK_SPINNER (WID ("connecting_spinner"))); + gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("connecting_notebook")), page); + if (page == CONNECTING_NOTEBOOK_PAGE_SWITCH) + gtk_spinner_start (GTK_SPINNER (WID ("connecting_spinner"))); +} + +static void +remove_connecting (CcBluetoothPanel *self, + const char *bdaddr) +{ + g_hash_table_remove (self->priv->connecting_devices, bdaddr); +} + +static void +add_connecting (CcBluetoothPanel *self, + const char *bdaddr) +{ + g_hash_table_insert (self->priv->connecting_devices, + g_strdup (bdaddr), + GINT_TO_POINTER (1)); +} + +static gboolean +is_connecting (CcBluetoothPanel *self, + const char *bdaddr) +{ + return GPOINTER_TO_INT (g_hash_table_lookup (self->priv->connecting_devices, + bdaddr)); +} + +typedef struct { + char *bdaddr; + CcBluetoothPanel *self; +} ConnectData; + +static void +connect_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CcBluetoothPanel *self; + char *bdaddr; + gboolean success; + ConnectData *data = (ConnectData *) user_data; + + success = bluetooth_client_connect_service_finish (BLUETOOTH_CLIENT (source_object), + res, NULL); + + self = data->self; + + /* Check whether the same device is now selected, and update the UI */ + bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + if (g_strcmp0 (bdaddr, data->bdaddr) == 0) { + GtkSwitch *button; + + button = GTK_SWITCH (WID ("switch_connection")); + /* Reset the switch if it failed */ + if (success == FALSE) + gtk_switch_set_active (button, !gtk_switch_get_active (button)); + set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH); + } + + remove_connecting (self, data->bdaddr); + + g_free (bdaddr); + g_object_unref (data->self); + g_free (data->bdaddr); + g_free (data); +} + +static void +switch_connected_active_changed (GtkSwitch *button, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + char *proxy; + GValue value = { 0, }; + ConnectData *data; + char *bdaddr; + + bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + if (is_connecting (self, bdaddr)) { + g_free (bdaddr); + return; + } + + if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "proxy", &value) == FALSE) { + g_warning ("Could not get D-Bus proxy for selected device"); + return; + } + proxy = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value))); + g_value_unset (&value); + + if (proxy == NULL) + return; + + data = g_new0 (ConnectData, 1); + data->bdaddr = bdaddr; + data->self = g_object_ref (self); + + bluetooth_client_connect_service (self->priv->client, + proxy, + gtk_switch_get_active (button), + NULL, + connect_done, + data); + + add_connecting (self, data->bdaddr); + set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER); + g_free (proxy); +} + +enum { + NOTEBOOK_PAGE_EMPTY = 0, + NOTEBOOK_PAGE_PROPS = 1 +}; + +static void +set_notebook_page (CcBluetoothPanel *self, + int page) +{ + gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("props_notebook")), page); +} + +static void +add_extra_setup_widgets (CcBluetoothPanel *self, + const char *bdaddr) +{ + GValue value = { 0 }; + char **uuids; + GList *list, *l; + GtkWidget *container; + + if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "uuids", &value) == FALSE) + return; + + uuids = (char **) g_value_get_boxed (&value); + list = bluetooth_plugin_manager_get_widgets (bdaddr, (const char **) uuids); + if (list == NULL) { + g_value_unset (&value); + return; + } + + container = WID ("additional_setup_box"); + for (l = list; l != NULL; l = l->next) { + GtkWidget *widget = l->data; + gtk_box_pack_start (GTK_BOX (container), widget, + FALSE, FALSE, 0); + gtk_widget_show_all (widget); + } + gtk_widget_show (container); + g_value_unset (&value); +} + +static void +remove_extra_setup_widgets (CcBluetoothPanel *self) +{ + GtkWidget *box; + + box = WID ("additional_setup_box"); + gtk_container_forall (GTK_CONTAINER (box), (GtkCallback) gtk_widget_destroy, NULL); + gtk_widget_hide (WID ("additional_setup_box")); +} + +static void +cc_bluetooth_panel_update_properties (CcBluetoothPanel *self) +{ + char *bdaddr; + GtkSwitch *button; + + button = GTK_SWITCH (WID ("switch_connection")); + g_signal_handlers_block_by_func (button, switch_connected_active_changed, self); + + /* Hide all the buttons now, and show them again if we need to */ + gtk_widget_hide (WID ("keyboard_box")); + gtk_widget_hide (WID ("sound_box")); + gtk_widget_hide (WID ("mouse_box")); + gtk_widget_hide (WID ("browse_box")); + gtk_widget_hide (WID ("send_box")); + + bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + + /* Remove the extra setup widgets */ + if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0) + remove_extra_setup_widgets (self); + + if (bdaddr == NULL) { + gtk_widget_set_sensitive (WID ("properties_vbox"), FALSE); + gtk_switch_set_active (button, FALSE); + gtk_widget_set_sensitive (WID ("button_delete"), FALSE); + set_notebook_page (self, NOTEBOOK_PAGE_EMPTY); + } else { + BluetoothType type; + gboolean connected; + GValue value = { 0 }; + GHashTable *services; + + if (self->priv->debug) + bluetooth_chooser_dump_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + + gtk_widget_set_sensitive (WID ("properties_vbox"), TRUE); + + if (is_connecting (self, bdaddr)) { + gtk_switch_set_active (button, TRUE); + set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER); + } else { + connected = bluetooth_chooser_get_selected_device_is_connected (BLUETOOTH_CHOOSER (self->priv->chooser)); + gtk_switch_set_active (button, connected); + set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH); + } + + /* Paired */ + bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "paired", &value); + gtk_label_set_text (GTK_LABEL (WID ("paired_label")), + g_value_get_boolean (&value) ? _("Yes") : _("No")); + g_value_unset (&value); + + /* Connection */ + bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "services", &value); + services = g_value_get_boxed (&value); + gtk_widget_set_sensitive (GTK_WIDGET (button), (services != NULL)); + g_value_unset (&value); + + /* UUIDs */ + if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "uuids", &value)) { + const char **uuids; + guint i; + + uuids = (const char **) g_value_get_boxed (&value); + for (i = 0; uuids && uuids[i] != NULL; i++) { + if (g_str_equal (uuids[i], "OBEXObjectPush")) + gtk_widget_show (WID ("send_box")); + else if (g_str_equal (uuids[i], "OBEXFileTransfer")) + gtk_widget_show (WID ("browse_box")); + } + g_value_unset (&value); + } + + /* Type */ + type = bluetooth_chooser_get_selected_device_type (BLUETOOTH_CHOOSER (self->priv->chooser)); + gtk_label_set_text (GTK_LABEL (WID ("type_label")), bluetooth_type_to_string (type)); + switch (type) { + case BLUETOOTH_TYPE_KEYBOARD: + gtk_widget_show (WID ("keyboard_box")); + break; + case BLUETOOTH_TYPE_MOUSE: + case BLUETOOTH_TYPE_TABLET: + gtk_widget_show (WID ("mouse_box")); + break; + case BLUETOOTH_TYPE_HEADSET: + case BLUETOOTH_TYPE_HEADPHONES: + case BLUETOOTH_TYPE_OTHER_AUDIO: + gtk_widget_show (WID ("sound_box")); + default: + /* others? */ + ; + } + + /* Extra widgets */ + if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0) + add_extra_setup_widgets (self, bdaddr); + + gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr); + + gtk_widget_set_sensitive (WID ("button_delete"), TRUE); + set_notebook_page (self, NOTEBOOK_PAGE_PROPS); + } + + g_free (self->priv->selected_bdaddr); + self->priv->selected_bdaddr = bdaddr; + + g_signal_handlers_unblock_by_func (button, switch_connected_active_changed, self); +} + +static void +power_callback (GObject *object, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + gboolean state; + + state = gtk_switch_get_active (GTK_SWITCH (WID ("switch_bluetooth"))); + g_debug ("Power switched to %s", state ? "off" : "on"); + bluetooth_killswitch_set_state (self->priv->killswitch, + state ? BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED : BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED); +} + +static void +cc_bluetooth_panel_update_treeview_message (CcBluetoothPanel *self, + const char *message) +{ + if (message != NULL) { + gtk_widget_hide (self->priv->chooser); + gtk_widget_show (WID ("message_scrolledwindow")); + + gtk_label_set_text (GTK_LABEL (WID ("message_label")), + message); + } else { + gtk_widget_hide (WID ("message_scrolledwindow")); + gtk_widget_show (self->priv->chooser); + } +} + +static void +cc_bluetooth_panel_update_power (CcBluetoothPanel *self) +{ + BluetoothKillswitchState state; + char *path; + gboolean powered, sensitive; + + g_object_get (G_OBJECT (self->priv->client), + "default-adapter", &path, + "default-adapter-powered", &powered, + NULL); + state = bluetooth_killswitch_get_state (self->priv->killswitch); + + g_debug ("Updating power, default adapter: %s (powered: %s), killswitch: %s", + path ? path : "(none)", + powered ? "on" : "off", + bluetooth_killswitch_state_to_string (state)); + + if (path == NULL && + bluetooth_killswitch_has_killswitches (self->priv->killswitch) && + state != BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) { + g_debug ("Default adapter is unpowered, but should be available"); + sensitive = TRUE; + cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled")); + } else if (path == NULL && + state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) { + g_debug ("Bluetooth is Hard blocked"); + sensitive = FALSE; + cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled by hardware switch")); + } else if (path == NULL) { + sensitive = FALSE; + g_debug ("No Bluetooth available"); + cc_bluetooth_panel_update_treeview_message (self, _("No Bluetooth adapters found")); + } else { + sensitive = TRUE; + g_debug ("Bluetooth is available and powered"); + cc_bluetooth_panel_update_treeview_message (self, NULL); + } + + g_free (path); + gtk_widget_set_sensitive (WID ("box_power") , sensitive); + gtk_widget_set_sensitive (WID ("box_vis") , sensitive); +} + +static void +switch_panel (CcBluetoothPanel *self, + const char *panel) +{ + CcShell *shell; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, panel, NULL, &error) == FALSE) + { + g_warning ("Failed to activate '%s' panel: %s", panel, error->message); + g_error_free (error); + } +} + +static gboolean +keyboard_callback (GtkButton *button, + CcBluetoothPanel *self) +{ + switch_panel (self, KEYBOARD_PREFS); + return TRUE; +} + +static gboolean +mouse_callback (GtkButton *button, + CcBluetoothPanel *self) +{ + switch_panel (self, MOUSE_PREFS); + return TRUE; +} + +static gboolean +sound_callback (GtkButton *button, + CcBluetoothPanel *self) +{ + switch_panel (self, SOUND_PREFS); + return TRUE; +} + +static void +send_callback (GtkButton *button, + CcBluetoothPanel *self) +{ + char *bdaddr, *alias; + + bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + alias = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser)); + + bluetooth_send_to_address (bdaddr, alias); + + g_free (bdaddr); + g_free (alias); +} + +static void +mount_finish_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + + if (bluetooth_browse_address_finish (source_object, res, &error) == FALSE) { + g_printerr ("Failed to mount OBEX volume: %s", error->message); + g_error_free (error); + return; + } +} + +static void +browse_callback (GtkButton *button, + CcBluetoothPanel *self) +{ + char *bdaddr; + + bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + + bluetooth_browse_address (G_OBJECT (self), bdaddr, + GDK_CURRENT_TIME, mount_finish_cb, NULL); + + g_free (bdaddr); +} + +/* Visibility/Discoverable */ +static void discoverable_changed (BluetoothClient *client, + GParamSpec *spec, + CcBluetoothPanel *self); + +static void +switch_discoverable_active_changed (GtkSwitch *button, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + g_signal_handlers_block_by_func (self->priv->client, discoverable_changed, self); + g_object_set (G_OBJECT (self->priv->client), "default-adapter-discoverable", + gtk_switch_get_active (button), NULL); + g_signal_handlers_unblock_by_func (self->priv->client, discoverable_changed, self); +} + +static void +cc_bluetooth_panel_update_visibility (CcBluetoothPanel *self) +{ + gboolean discoverable; + GtkSwitch *button; + char *name; + + button = GTK_SWITCH (WID ("switch_discoverable")); + g_object_get (G_OBJECT (self->priv->client), "default-adapter-discoverable", &discoverable, NULL); + g_signal_handlers_block_by_func (button, switch_discoverable_active_changed, self); + gtk_switch_set_active (button, discoverable); + g_signal_handlers_unblock_by_func (button, switch_discoverable_active_changed, self); + + g_object_get (G_OBJECT (self->priv->client), "default-adapter-name", &name, NULL); + if (name == NULL) { + gtk_widget_set_sensitive (WID ("switch_discoverable"), FALSE); + gtk_widget_set_sensitive (WID ("visible_label"), FALSE); + gtk_label_set_text (GTK_LABEL (WID ("visible_label")), _("Visibility")); + } else { + char *label; + + label = g_strdup_printf (_("Visibility of “%s”"), name); + g_free (name); + gtk_label_set_text (GTK_LABEL (WID ("visible_label")), label); + g_free (label); + + gtk_widget_set_sensitive (WID ("switch_discoverable"), TRUE); + gtk_widget_set_sensitive (WID ("visible_label"), TRUE); + } +} + +static void +discoverable_changed (BluetoothClient *client, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + cc_bluetooth_panel_update_visibility (self); +} + +static void +name_changed (BluetoothClient *client, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + cc_bluetooth_panel_update_visibility (self); +} + +static void +device_selected_changed (BluetoothChooser *chooser, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + cc_bluetooth_panel_update_properties (self); +} + +static gboolean +show_confirm_dialog (CcBluetoothPanel *self, + const char *name) +{ + GtkWidget *dialog, *parent; + gint response; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (self)); + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + _("Remove '%s' from the list of devices?"), name); + g_object_set (G_OBJECT (dialog), "secondary-text", + _("If you remove the device, you will have to set it up again before next use."), + NULL); + + gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_REMOVE, GTK_RESPONSE_ACCEPT); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + + if (response == GTK_RESPONSE_ACCEPT) + return TRUE; + + return FALSE; +} + +static gboolean +remove_selected_device (CcBluetoothPanel *self) +{ + GValue value = { 0, }; + char *device, *adapter; + GDBusProxy *adapter_proxy; + GError *error = NULL; + GVariant *ret; + + if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser), + "proxy", &value) == FALSE) { + return FALSE; + } + device = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value))); + g_value_unset (&value); + + g_object_get (G_OBJECT (self->priv->client), "default-adapter", &adapter, NULL); + adapter_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + "org.bluez", + adapter, + "org.bluez.Adapter", + NULL, + &error); + g_free (adapter); + if (adapter_proxy == NULL) { + g_warning ("Failed to create a GDBusProxy for the default adapter: %s", error->message); + g_error_free (error); + g_free (device); + return FALSE; + } + + ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (adapter_proxy), + "RemoveDevice", + g_variant_new ("(o)", device), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (ret == NULL) { + g_warning ("Failed to remove device '%s': %s", device, error->message); + g_error_free (error); + } else { + g_variant_unref (ret); + } + + g_object_unref (adapter_proxy); + g_free (device); + + return (ret != NULL); +} + +/* Treeview buttons */ +static void +delete_clicked (GtkToolButton *button, + CcBluetoothPanel *self) +{ + char *address, *name; + + address = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser)); + g_assert (address); + + name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser)); + + if (show_confirm_dialog (self, name) != FALSE) { + if (remove_selected_device (self)) + bluetooth_plugin_manager_device_deleted (address); + } + + g_free (address); + g_free (name); +} + +static void +setup_clicked (GtkToolButton *button, + CcBluetoothPanel *self) +{ + launch_command (WIZARD); +} + +/* Overall device state */ +static void +cc_bluetooth_panel_update_state (CcBluetoothPanel *self) +{ + char *bdaddr; + + g_object_get (G_OBJECT (self->priv->client), + "default-adapter", &bdaddr, + NULL); + gtk_widget_set_sensitive (WID ("toolbar"), (bdaddr != NULL)); + g_free (bdaddr); +} + +static void +cc_bluetooth_panel_update_powered_state (CcBluetoothPanel *self) +{ + gboolean powered; + + g_object_get (G_OBJECT (self->priv->client), + "default-adapter-powered", &powered, + NULL); + gtk_switch_set_active (GTK_SWITCH (WID ("switch_bluetooth")), powered); +} + +static void +default_adapter_power_changed (BluetoothClient *client, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + g_debug ("Default adapter power changed"); + cc_bluetooth_panel_update_powered_state (self); +} + +static void +default_adapter_changed (BluetoothClient *client, + GParamSpec *spec, + CcBluetoothPanel *self) +{ + g_debug ("Default adapter changed"); + cc_bluetooth_panel_update_state (self); + cc_bluetooth_panel_update_power (self); + cc_bluetooth_panel_update_powered_state (self); +} + +static void +killswitch_changed (BluetoothKillswitch *killswitch, + BluetoothKillswitchState state, + CcBluetoothPanel *self) +{ + g_debug ("Killswitch changed to state '%s' (%d)", bluetooth_killswitch_state_to_string (state) , state); + cc_bluetooth_panel_update_state (self); + cc_bluetooth_panel_update_power (self); +} + +static void +cc_bluetooth_panel_init (CcBluetoothPanel *self) +{ + GtkWidget *widget; + GError *error = NULL; + GtkStyleContext *context; + + self->priv = BLUETOOTH_PANEL_PRIVATE (self); + + bluetooth_plugin_manager_init (); + self->priv->killswitch = bluetooth_killswitch_new (); + self->priv->client = bluetooth_client_new (); + self->priv->connecting_devices = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); + self->priv->debug = g_getenv ("BLUETOOTH_DEBUG") != NULL; + + self->priv->builder = gtk_builder_new (); + gtk_builder_set_translation_domain (self->priv->builder, GETTEXT_PACKAGE); + gtk_builder_add_from_file (self->priv->builder, + PKGDATADIR "/bluetooth.ui", + &error); + if (error != NULL) { + g_warning ("Failed to load '%s': %s", PKGDATADIR "/bluetooth.ui", error->message); + g_error_free (error); + return; + } + + widget = WID ("grid"); + gtk_widget_reparent (widget, GTK_WIDGET (self)); + + /* Overall device state */ + cc_bluetooth_panel_update_state (self); + g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter", + G_CALLBACK (default_adapter_changed), self); + g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-powered", + G_CALLBACK (default_adapter_power_changed), self); + + /* The discoverable button */ + cc_bluetooth_panel_update_visibility (self); + g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-discoverable", + G_CALLBACK (discoverable_changed), self); + g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-name", + G_CALLBACK (name_changed), self); + g_signal_connect (G_OBJECT (WID ("switch_discoverable")), "notify::active", + G_CALLBACK (switch_discoverable_active_changed), self); + + /* The known devices */ + widget = WID ("devices_table"); + + context = gtk_widget_get_style_context (WID ("message_scrolledwindow")); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + + /* Note that this will only ever show the devices on the default + * adapter, this is on purpose */ + self->priv->chooser = bluetooth_chooser_new (); + gtk_box_pack_start (GTK_BOX (WID ("box_devices")), self->priv->chooser, TRUE, TRUE, 0); + g_object_set (self->priv->chooser, + "show-searching", FALSE, + "show-device-type", FALSE, + "show-device-type-column", FALSE, + "show-device-category", FALSE, + "show-pairing", FALSE, + "show-connected", FALSE, + "device-category-filter", BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED, + "no-show-all", TRUE, + NULL); + + /* Join treeview and buttons */ + widget = bluetooth_chooser_get_scrolled_window (BLUETOOTH_CHOOSER (self->priv->chooser)); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), 250); + gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (widget), 200); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + widget = WID ("toolbar"); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + g_signal_connect (G_OBJECT (self->priv->chooser), "notify::device-selected", + G_CALLBACK (device_selected_changed), self); + g_signal_connect (G_OBJECT (WID ("button_delete")), "clicked", + G_CALLBACK (delete_clicked), self); + g_signal_connect (G_OBJECT (WID ("button_setup")), "clicked", + G_CALLBACK (setup_clicked), self); + + /* Set the initial state of the properties */ + cc_bluetooth_panel_update_properties (self); + g_signal_connect (G_OBJECT (WID ("mouse_link")), "activate-link", + G_CALLBACK (mouse_callback), self); + g_signal_connect (G_OBJECT (WID ("keyboard_link")), "activate-link", + G_CALLBACK (keyboard_callback), self); + g_signal_connect (G_OBJECT (WID ("sound_link")), "activate-link", + G_CALLBACK (sound_callback), self); + g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked", + G_CALLBACK (browse_callback), self); + g_signal_connect (G_OBJECT (WID ("send_button")), "clicked", + G_CALLBACK (send_callback), self); + g_signal_connect (G_OBJECT (WID ("switch_connection")), "notify::active", + G_CALLBACK (switch_connected_active_changed), self); + + /* Set the initial state of power */ + g_signal_connect (G_OBJECT (WID ("switch_bluetooth")), "notify::active", + G_CALLBACK (power_callback), self); + g_signal_connect (G_OBJECT (self->priv->killswitch), "state-changed", + G_CALLBACK (killswitch_changed), self); + cc_bluetooth_panel_update_power (self); + + gtk_widget_show_all (GTK_WIDGET (self)); +} + +void +cc_bluetooth_panel_register (GIOModule *module) +{ + cc_bluetooth_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_BLUETOOTH_PANEL, + "bluetooth", 0); +} + +/* GIO extension stuff */ +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + /* register the panel */ + cc_bluetooth_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/color/cc-color-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/color/cc-color-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/color/cc-color-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/color/cc-color-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2580 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2011 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include +#include + +#include "cc-color-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcColorPanel, cc_color_panel) + +#define COLOR_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_COLOR_PANEL, CcColorPanelPrivate)) + +struct _CcColorPanelPrivate +{ + CdClient *client; + CdDevice *current_device; + CdSensor *sensor; + GCancellable *cancellable; + GDBusProxy *proxy; + GSettings *settings; + GtkBuilder *builder; + GtkTreeStore *list_store_devices; + GtkWidget *main_window; +}; + +enum { + GCM_PREFS_COLUMN_DEVICE_PATH, + GCM_PREFS_COLUMN_SORT, + GCM_PREFS_COLUMN_ICON, + GCM_PREFS_COLUMN_TITLE, + GCM_PREFS_COLUMN_DEVICE, + GCM_PREFS_COLUMN_PROFILE, + GCM_PREFS_COLUMN_STATUS, + GCM_PREFS_COLUMN_STATUS_IMAGE, + GCM_PREFS_COLUMN_TOOLTIP, + GCM_PREFS_COLUMN_RADIO_ACTIVE, + GCM_PREFS_COLUMN_RADIO_VISIBLE, + GCM_PREFS_COLUMN_NUM_COLUMNS +}; + +enum { + GCM_PREFS_COMBO_COLUMN_TEXT, + GCM_PREFS_COMBO_COLUMN_PROFILE, + GCM_PREFS_COMBO_COLUMN_TYPE, + GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS +}; + +typedef enum { + GCM_PREFS_ENTRY_TYPE_PROFILE, + GCM_PREFS_ENTRY_TYPE_IMPORT +} GcmPrefsEntryType; + +#define GCM_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.color" +#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold" +#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold" + +/* max number of devices and profiles to cause auto-expand at startup */ +#define GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED 5 + +static void gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs); + +static void +gcm_prefs_combobox_add_profile (GtkWidget *widget, + CdProfile *profile, + GcmPrefsEntryType entry_type, + GtkTreeIter *iter) +{ + const gchar *id; + GtkTreeModel *model; + GtkTreeIter iter_tmp; + GString *string; + + /* iter is optional */ + if (iter == NULL) + iter = &iter_tmp; + + /* use description */ + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + /* TRANSLATORS: this is where the user can click and import a profile */ + string = g_string_new (_("Other profile…")); + } + else + { + string = g_string_new (cd_profile_get_title (profile)); + + /* any source prefix? */ + id = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile has been auto-generated for this hardware */ + g_string_prepend (string, _("Default: ")); + } +#if CD_CHECK_VERSION(0,1,14) + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile his a standard space like AdobeRGB */ + g_string_prepend (string, _("Colorspace: ")); + } + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile is a test profile */ + g_string_prepend (string, _("Test profile: ")); + } +#endif + } + + /* also add profile */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_list_store_append (GTK_LIST_STORE(model), iter); + gtk_list_store_set (GTK_LIST_STORE(model), iter, + GCM_PREFS_COMBO_COLUMN_TEXT, string->str, + GCM_PREFS_COMBO_COLUMN_PROFILE, profile, + GCM_PREFS_COMBO_COLUMN_TYPE, entry_type, + -1); + g_string_free (string, TRUE); +} + +static void +gcm_prefs_default_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdProfile *profile; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* TODO: check if the profile is already systemwide */ + profile = cd_device_get_default_profile (priv->current_device); + if (profile == NULL) + goto out; + + /* install somewhere out of $HOME */ + ret = cd_profile_install_system_wide_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to set profile system-wide: %s", + error->message); + g_error_free (error); + goto out; + } +out: + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_treeview_popup_menu (CcColorPanel *prefs, GtkWidget *treeview) +{ + GtkWidget *menu, *menuitem; + + menu = gtk_menu_new (); + + /* TRANSLATORS: this is when the profile should be set for all users */ + menuitem = gtk_menu_item_new_with_label (_("Set for all users")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (gcm_prefs_default_cb), + prefs); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + /* TRANSLATORS: this is when the profile should be set for all users */ + menuitem = gtk_menu_item_new_with_label (_("Create virtual device")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (gcm_prefs_device_add_cb), + prefs); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + gtk_widget_show_all (menu); + + /* Note: gdk_event_get_time() accepts a NULL argument */ + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, + gdk_event_get_time (NULL)); +} + +static gboolean +gcm_prefs_treeview_popup_menu_cb (GtkWidget *treeview, CcColorPanel *prefs) +{ + if (prefs->priv->current_device == NULL) + return FALSE; + gcm_prefs_treeview_popup_menu (prefs, treeview); + return TRUE; /* we handled this */ +} + +static GFile * +gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs) +{ + GtkWindow *window; + GtkWidget *dialog; + GFile *file = NULL; + GtkFileFilter *filter; + CcColorPanelPrivate *priv = prefs->priv; + + /* create new dialog */ + window = GTK_WINDOW(gtk_builder_get_object (priv->builder, + "dialog_assign")); + /* TRANSLATORS: an ICC profile is a file containing colorspace data */ + dialog = gtk_file_chooser_dialog_new (_("Select ICC Profile File"), window, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Import"), GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), g_get_home_dir ()); + gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE); + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), FALSE); + + /* setup the filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile"); + + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("Supported ICC profiles")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* setup the all files filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filter, "*"); + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("All files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* did user choose file */ + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog)); + + /* we're done */ + gtk_widget_destroy (dialog); + + /* or NULL for missing */ + return file; +} + +static void +gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + gboolean ret; + GError *error = NULL; + guint xid; + GPtrArray *argv; + CcColorPanelPrivate *priv = prefs->priv; + + /* get xid */ + xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + + /* run with modal set */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-calibrate", NULL)); + g_ptr_array_add (argv, g_strdup ("--device")); + g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + if (!ret) + { + g_warning ("failed to run calibrate: %s", error->message); + g_error_free (error); + } + g_ptr_array_unref (argv); +} + +static void +gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + + /* show ui */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_show (widget); + gtk_window_set_transient_for (GTK_WINDOW (widget), + GTK_WINDOW (priv->main_window)); + + /* clear entries */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_model")); + gtk_entry_set_text (GTK_ENTRY (widget), ""); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_manufacturer")); + gtk_entry_set_text (GTK_ENTRY (widget), ""); +} + +static gboolean +gcm_prefs_is_profile_suitable_for_device (CdProfile *profile, + CdDevice *device) +{ +#if CD_CHECK_VERSION(0,1,14) + const gchar *data_source; +#endif + CdProfileKind profile_kind_tmp; + CdProfileKind profile_kind; + CdColorspace profile_colorspace; + CdColorspace device_colorspace = 0; + gboolean ret = FALSE; + CdDeviceKind device_kind; + + /* not the right colorspace */ + device_colorspace = cd_device_get_colorspace (device); + profile_colorspace = cd_profile_get_colorspace (profile); + if (device_colorspace != profile_colorspace) + goto out; + + /* not the correct kind */ + device_kind = cd_device_get_kind (device); + profile_kind_tmp = cd_profile_get_kind (profile); + profile_kind = cd_device_kind_to_profile_kind (device_kind); + if (profile_kind_tmp != profile_kind) + goto out; + +#if CD_CHECK_VERSION(0,1,14) + /* ignore the colorspace profiles */ + data_source = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + goto out; +#endif + + /* success */ + ret = TRUE; +out: + return ret; +} + +static gint +gcm_prefs_combo_sort_func_cb (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gint type_a, type_b; + gchar *text_a; + gchar *text_b; + gint retval; + + /* get data from model */ + gtk_tree_model_get (model, a, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_a, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_a, + -1); + gtk_tree_model_get (model, b, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_b, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_b, + -1); + + /* prefer normal type profiles over the 'Other Profile...' entry */ + if (type_a < type_b) + retval = -1; + else if (type_a > type_b) + retval = 1; + else + retval = g_strcmp0 (text_a, text_b); + + g_free (text_a); + g_free (text_b); + return retval; +} + +static gboolean +gcm_prefs_combo_set_default_cb (gpointer user_data) +{ + GtkWidget *widget = GTK_WIDGET (user_data); + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + return FALSE; +} + +static gboolean +gcm_prefs_profile_exists_in_array (GPtrArray *array, CdProfile *profile) +{ + CdProfile *profile_tmp; + guint i; + + for (i = 0; i < array->len; i++) + { + profile_tmp = g_ptr_array_index (array, i); + if (cd_profile_equal (profile, profile_tmp)) + return TRUE; + } + return FALSE; +} + +static void +gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs, + GtkWidget *widget, + GPtrArray *profiles) +{ + CdProfile *profile_tmp; + gboolean ret; + GError *error = NULL; + GPtrArray *profile_array = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + guint i; + CcColorPanelPrivate *priv = prefs->priv; + + /* clear existing entries */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + gtk_list_store_clear (GTK_LIST_STORE (model)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + GCM_PREFS_COMBO_COLUMN_TEXT, + GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), + GCM_PREFS_COMBO_COLUMN_TEXT, + gcm_prefs_combo_sort_func_cb, + model, NULL); + + /* get profiles */ + profile_array = cd_client_get_profiles_sync (priv->client, + priv->cancellable, + &error); + if (profile_array == NULL) + { + g_warning ("failed to get profiles: %s", + error->message); + g_error_free (error); + goto out; + } + + /* add profiles of the right kind */ + for (i = 0; i < profile_array->len; i++) + { + profile_tmp = g_ptr_array_index (profile_array, i); + + /* get properties */ + ret = cd_profile_connect_sync (profile_tmp, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + + /* don't add any of the already added profiles */ + if (profiles != NULL) + { + if (gcm_prefs_profile_exists_in_array (profiles, profile_tmp)) + continue; + } + + /* only add correct types */ + ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp, + priv->current_device); + if (!ret) + continue; + +#if CD_CHECK_VERSION(0,1,13) + /* ignore profiles from other user accounts */ + if (!cd_profile_has_access (profile_tmp)) + continue; +#endif + + /* add */ + gcm_prefs_combobox_add_profile (widget, + profile_tmp, + GCM_PREFS_ENTRY_TYPE_PROFILE, + &iter); + } + + /* add a import entry */ +#if CD_CHECK_VERSION(0,1,12) + gcm_prefs_combobox_add_profile (widget, NULL, GCM_PREFS_ENTRY_TYPE_IMPORT, NULL); +#endif + g_idle_add (gcm_prefs_combo_set_default_cb, widget); +out: + if (profile_array != NULL) + g_ptr_array_unref (profile_array); +} + +static void +gcm_prefs_profile_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + const gchar *title; + GPtrArray *profiles; + CcColorPanelPrivate *priv = prefs->priv; + + /* add profiles of the right kind */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + profiles = cd_device_get_profiles (priv->current_device); + gcm_prefs_add_profiles_suitable_for_devices (prefs, widget, profiles); + + /* set the title */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_assign_title")); + switch (cd_device_get_kind (priv->current_device)) { + case CD_DEVICE_KIND_DISPLAY: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Displays"); + break; + case CD_DEVICE_KIND_SCANNER: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Scanners"); + break; + case CD_DEVICE_KIND_PRINTER: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Printers"); + break; + case CD_DEVICE_KIND_CAMERA: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Cameras"); + break; + case CD_DEVICE_KIND_WEBCAM: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Webcams"); + break; + default: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI + * where the device type is not recognised */ + title = _("Available Profiles"); + break; + } + gtk_label_set_label (GTK_LABEL (widget), title); + + /* show the dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_show (widget); + gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (priv->main_window)); + if (profiles != NULL) + g_ptr_array_unref (profiles); +} + +static void +gcm_prefs_profile_remove_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *model; + gboolean ret = FALSE; + CdProfile *profile = NULL; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the selected row */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + goto out; + + /* if the profile is default, then we'll have to make the first profile default */ + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* just remove it, the list store will get ::changed */ + ret = cd_device_remove_profile_sync (priv->current_device, + profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to remove profile: %s", error->message); + g_error_free (error); + goto out; + } +out: + if (profile != NULL) + g_object_unref (profile); + return; +} + +static void +gcm_prefs_make_profile_default_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CdDevice *device = CD_DEVICE (object); + gboolean ret = FALSE; + GError *error = NULL; + + ret = cd_device_make_profile_default_finish (device, + res, + &error); + if (!ret) + { + g_warning ("failed to set default profile on %s: %s", + cd_device_get_id (device), + error->message); + g_error_free (error); + } +} + +static void +gcm_prefs_profile_make_default_internal (CcColorPanel *prefs, + GtkTreeModel *model, + GtkTreeIter *iter_selected) +{ + CdDevice *device; + CdProfile *profile; + CcColorPanelPrivate *priv = prefs->priv; + + /* get currentlt selected item */ + gtk_tree_model_get (model, iter_selected, + GCM_PREFS_COLUMN_DEVICE, &device, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + if (profile == NULL || device == NULL) + goto out; + + /* just set it default */ + g_debug ("setting %s default on %s", + cd_profile_get_id (profile), + cd_device_get_id (device)); + cd_device_make_profile_default (device, + profile, + priv->cancellable, + gcm_prefs_make_profile_default_cb, + prefs); +out: + if (profile != NULL) + g_object_unref (profile); + if (device != NULL) + g_object_unref (device); +} + +static void +gcm_prefs_profile_view_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdProfile *profile = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + gchar *options = NULL; + GPtrArray *argv = NULL; + guint xid; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the selected row */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + g_assert_not_reached (); + + /* get currentlt selected item */ + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* get xid */ + xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + + /* open up gcm-viewer as a info pane */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-viewer", NULL)); + g_ptr_array_add (argv, g_strdup ("--profile")); + g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + if (!ret) + { + g_warning ("failed to run calibrate: %s", error->message); + g_error_free (error); + } + + g_ptr_array_unref (argv); + g_free (options); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_button_assign_cancel_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); +} + +static void +gcm_prefs_button_assign_ok_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeModel *model; + CdProfile *profile = NULL; + gboolean ret = FALSE; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* hide window */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); + + /* get entry */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + goto out; + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, &profile, + -1); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + goto out; + } + + /* just add it, the list store will get ::changed */ + ret = cd_device_add_profile_sync (priv->current_device, + CD_DEVICE_RELATION_HARD, + profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to add: %s", error->message); + g_error_free (error); + goto out; + } + + /* make it default */ + cd_device_make_profile_default (priv->current_device, + profile, + priv->cancellable, + gcm_prefs_make_profile_default_cb, + prefs); +out: + if (profile != NULL) + g_object_unref (profile); +} + +static gboolean +gcm_prefs_profile_delete_event_cb (GtkWidget *widget, + GdkEvent *event, + CcColorPanel *prefs) +{ + gcm_prefs_button_assign_cancel_cb (widget, prefs); + return TRUE; +} + +static void +gcm_prefs_delete_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + gboolean ret = FALSE; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* try to delete device */ + ret = cd_client_delete_device_sync (priv->client, + priv->current_device, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to delete device: %s", error->message); + g_error_free (error); + } +} + +static void +gcm_prefs_treeview_renderer_toggled (GtkCellRendererToggle *cell, + const gchar *path, CcColorPanel *prefs) +{ + gboolean ret; + GtkTreeModel *model; + GtkTreeIter iter; + CcColorPanelPrivate *priv = prefs->priv; + + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_from_string (model, &iter, path); + if (!ret) + return; + gcm_prefs_profile_make_default_internal (prefs, model, &iter); +} + +static void +gcm_prefs_add_devices_columns (CcColorPanel *prefs, + GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + CcColorPanelPrivate *priv = prefs->priv; + + gtk_tree_view_set_headers_visible (treeview, TRUE); + + /* --- column for device image and device title --- */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + /* TRANSLATORS: column for device list */ + gtk_tree_view_column_set_title (column, _("Device")); + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", GCM_PREFS_COLUMN_ICON); + + /* option */ + renderer = gtk_cell_renderer_toggle_new (); + g_signal_connect (renderer, "toggled", + G_CALLBACK (gcm_prefs_treeview_renderer_toggled), prefs); + g_object_set (renderer, "radio", TRUE, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "active", GCM_PREFS_COLUMN_RADIO_ACTIVE); + gtk_tree_view_column_add_attribute (column, renderer, + "visible", GCM_PREFS_COLUMN_RADIO_VISIBLE); + + /* text */ + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", GCM_PREFS_COLUMN_TITLE); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->list_store_devices), + GCM_PREFS_COLUMN_SORT, + GTK_SORT_DESCENDING); + gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column)); + + /* --- column for device status --- */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + /* TRANSLATORS: column for device list */ + gtk_tree_view_column_set_title (column, _("Calibration")); + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", GCM_PREFS_COLUMN_STATUS_IMAGE); + + /* text */ + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", GCM_PREFS_COLUMN_STATUS); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column)); + + /* tooltip */ + gtk_tree_view_set_tooltip_column (treeview, + GCM_PREFS_COLUMN_TOOLTIP); +} + +static void +gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *prefs) +{ + gboolean ret = FALSE; + GtkWidget *widget; + const gchar *tooltip; + CdDeviceKind kind; + CcColorPanelPrivate *priv = prefs->priv; + + /* TRANSLATORS: this is when the button is sensitive */ + tooltip = _("Create a color profile for the selected device"); + + /* no device selected */ + if (priv->current_device == NULL) + goto out; + + /* are we a display */ + kind = cd_device_get_kind (priv->current_device); + if (kind == CD_DEVICE_KIND_DISPLAY) + { + + /* find whether we have hardware installed */ + if (priv->sensor == NULL) { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_SCANNER || + kind == CD_DEVICE_KIND_CAMERA || + kind == CD_DEVICE_KIND_WEBCAM) + { + + /* TODO: find out if we can scan using gnome-scan */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_PRINTER) + { + + /* find whether we have hardware installed */ + if (priv->sensor == NULL) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* find whether we have hardware installed */ + ret = cd_sensor_has_cap (priv->sensor, CD_SENSOR_CAP_PRINTER); + if (!ret) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument does not support printer profiling."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The device type is not currently supported."); + } +out: + /* control the tooltip and sensitivity of the button */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + gtk_widget_set_tooltip_text (widget, tooltip); + gtk_widget_set_sensitive (widget, ret); +} + +static void +gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device) +{ + GtkWidget *widget; + CdDeviceMode device_mode; + CcColorPanelPrivate *priv = prefs->priv; + + if (device == NULL) + g_assert_not_reached (); + + /* get current device */ + if (priv->current_device != NULL) + g_object_unref (priv->current_device); + priv->current_device = g_object_ref (device); + + /* we have a new device */ + g_debug ("selected device is: %s", + cd_device_get_id (device)); + + /* make sure selectable */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + gtk_widget_set_sensitive (widget, TRUE); + + /* can we delete this device? */ + device_mode = cd_device_get_mode (priv->current_device); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + gtk_widget_set_visible (widget, device_mode == CD_DEVICE_MODE_VIRTUAL); + + /* can this device calibrate */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static void +gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device) +{ + GtkWidget *widget; + CdDeviceRelation relation; + gchar *s; + CcColorPanelPrivate *priv = prefs->priv; + + /* get profile */ + g_debug ("selected profile = %s", + cd_profile_get_filename (profile)); + + + /* find the profile relationship */ + relation = cd_device_get_profile_relation_sync (device, + profile, + NULL, NULL); + + /* we can only remove hard relationships */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + if (relation == CD_DEVICE_RELATION_HARD) + { + gtk_widget_set_tooltip_text (widget, ""); + gtk_widget_set_sensitive (widget, TRUE); + } + else + { + /* TRANSLATORS: this is when an auto-added profile cannot be removed */ + gtk_widget_set_tooltip_text (widget, _("Cannot remove automatically added profile")); + gtk_widget_set_sensitive (widget, FALSE); + } + + /* allow getting profile info */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + if ((s = g_find_program_in_path ("gcm-viewer"))) + { + gtk_widget_set_sensitive (widget, TRUE); + g_free (s); + } + else + gtk_widget_set_sensitive (widget, FALSE); + + /* hide device specific stuff */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + gtk_widget_set_visible (widget, FALSE); +} + +static void +gcm_prefs_devices_treeview_clicked_cb (GtkTreeSelection *selection, + CcColorPanel *prefs) +{ + GtkTreeModel *model; + GtkTreeIter iter; + CdDevice *device = NULL; + CdProfile *profile = NULL; + GtkWidget *widget; + CcColorPanelPrivate *priv = prefs->priv; + + /* get selection */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE, &device, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* device actions */ + if (device != NULL) + gcm_prefs_device_clicked (prefs, device); + if (profile != NULL) + gcm_prefs_profile_clicked (prefs, profile, device); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_default")); + gtk_widget_set_visible (widget, profile != NULL); + if (profile) + gtk_widget_set_sensitive (widget, !cd_profile_get_is_system_wide (profile)); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_add")); + gtk_widget_set_visible (widget, FALSE); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + gtk_widget_set_visible (widget, device != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_add")); + gtk_widget_set_visible (widget, device != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + gtk_widget_set_visible (widget, profile != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + gtk_widget_set_visible (widget, profile != NULL); + + /* if no buttons then hide toolbar */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbar_devices")); + gtk_widget_set_visible (widget, profile != NULL || device != NULL); + + if (device != NULL) + g_object_unref (device); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_treeview_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + CcColorPanel *prefs) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the iter */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter (model, &iter, path); + if (!ret) + return; + + /* make this profile the default */ + gcm_prefs_profile_make_default_internal (prefs, model, &iter); +} + +static const gchar * +gcm_prefs_device_kind_to_sort (CdDeviceKind kind) +{ + if (kind == CD_DEVICE_KIND_DISPLAY) + return "4"; + if (kind == CD_DEVICE_KIND_SCANNER) + return "3"; + if (kind == CD_DEVICE_KIND_CAMERA) + return "2"; + if (kind == CD_DEVICE_KIND_PRINTER) + return "1"; + return "0"; +} + +static gchar * +gcm_device_get_title (CdDevice *device) +{ + const gchar *model; + const gchar *vendor; + GString *string; + + /* try to get a nice string suitable for display */ + vendor = cd_device_get_vendor (device); + model = cd_device_get_model (device); + string = g_string_new (""); + + if (vendor != NULL && model != NULL) + { + g_string_append_printf (string, "%s - %s", + vendor, model); + goto out; + } + + /* just model */ + if (model != NULL) + { + g_string_append (string, model); + goto out; + } + + /* just vendor */ + if (vendor != NULL) + { + g_string_append (string, vendor); + goto out; + } + + /* fallback to id */ + g_string_append (string, cd_device_get_id (device)); +out: + return g_string_free (string, FALSE); +} + +static void +gcm_prefs_set_combo_simple_text (GtkWidget *combo_box) +{ + GtkCellRenderer *renderer; + GtkListStore *store; + + store = gtk_list_store_new (GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + CD_TYPE_PROFILE, + G_TYPE_UINT); + gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "ellipsize", PANGO_ELLIPSIZE_END, + "wrap-mode", PANGO_WRAP_WORD_CHAR, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", GCM_PREFS_COMBO_COLUMN_TEXT, + NULL); +} + +static void +gcm_prefs_profile_combo_changed_cb (GtkWidget *widget, + CcColorPanel *prefs) +{ + GFile *file = NULL; + GError *error = NULL; + gboolean ret; + CdProfile *profile = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + GcmPrefsEntryType entry_type; + CcColorPanelPrivate *priv = prefs->priv; + + /* no devices */ + if (priv->current_device == NULL) + return; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type, + -1); + + /* import */ + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + file = gcm_prefs_file_chooser_get_icc_profile (prefs); + if (file == NULL) + { + g_warning ("failed to get ICC file"); + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + + /* if we've got no other existing profiles to choose, then + * just close the assign dialog */ + gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type, + -1); + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); + } + goto out; + } + +#if CD_CHECK_VERSION(0,1,12) + profile = cd_client_import_profile_sync (priv->client, + file, + priv->cancellable, + &error); + if (profile == NULL) + { + g_warning ("failed to get imported profile: %s", error->message); + g_error_free (error); + goto out; + } +#endif + + /* add to combobox */ + gtk_list_store_append (GTK_LIST_STORE(model), &iter); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, profile, + -1); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + } +out: + if (file != NULL) + g_object_unref (file); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_sensor_coldplug (CcColorPanel *prefs) +{ + GPtrArray *sensors; + GError *error = NULL; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* unref old */ + if (priv->sensor != NULL) + { + g_object_unref (priv->sensor); + priv->sensor = NULL; + } + + /* no present */ + sensors = cd_client_get_sensors_sync (priv->client, NULL, &error); + if (sensors == NULL) + { + g_warning ("%s", error->message); + g_error_free (error); + goto out; + } + if (sensors->len == 0) + goto out; + + /* save a copy of the sensor */ + priv->sensor = g_object_ref (g_ptr_array_index (sensors, 0)); + + /* connect to the sensor */ + ret = cd_sensor_connect_sync (priv->sensor, NULL, &error); + if (!ret) + { + g_warning ("%s", error->message); + g_error_free (error); + goto out; + } +out: + if (sensors != NULL) + g_ptr_array_unref (sensors); +} + +static void +gcm_prefs_client_sensor_changed_cb (CdClient *client, + CdSensor *sensor, + CcColorPanel *prefs) +{ + gcm_prefs_sensor_coldplug (prefs); + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static const gchar * +gcm_prefs_device_kind_to_icon_name (CdDeviceKind kind) +{ + switch (kind) { + case CD_DEVICE_KIND_DISPLAY: + return "video-display"; + case CD_DEVICE_KIND_SCANNER: + return "scanner"; + case CD_DEVICE_KIND_PRINTER: + return "printer"; + case CD_DEVICE_KIND_CAMERA: + return "camera-photo"; + case CD_DEVICE_KIND_WEBCAM: + return "camera-web"; + default: + return "image-missing"; + } +} + +static GString * +gcm_prefs_get_profile_age_as_string (CdProfile *profile) +{ + const gchar *id; + gint64 age; + GString *string = NULL; + + if (profile == NULL) + { + /* TRANSLATORS: this is when there is no profile for the device */ + string = g_string_new (_("No profile")); + goto out; + } + + /* don't show details for EDID, colorspace or test profiles */ + id = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0) + goto out; +#if CD_CHECK_VERSION(0,1,14) + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + goto out; + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0) + goto out; +#endif + + /* days */ + age = cd_profile_get_age (profile); + if (age == 0) + { + string = g_string_new (NULL); + goto out; + } + age /= 60 * 60 * 24; + string = g_string_new (""); + + /* approximate years */ + if (age > 365) + { + age /= 365; + g_string_append_printf (string, ngettext ( + "%i year", + "%i years", + age), (guint) age); + goto out; + } + + /* approximate months */ + if (age > 30) + { + age /= 30; + g_string_append_printf (string, ngettext ( + "%i month", + "%i months", + age), (guint) age); + goto out; + } + + /* approximate weeks */ + if (age > 7) + { + age /= 7; + g_string_append_printf (string, ngettext ( + "%i week", + "%i weeks", + age), (guint) age); + goto out; + } + + /* fallback */ + g_string_append_printf (string, _("Less than 1 week")); +out: + return string; +} + +static gchar * +gcm_prefs_get_profile_created_for_sort (CdProfile *profile) +{ + gint64 created; + gchar *string = NULL; + GDateTime *dt = NULL; + + /* get profile age */ + created = cd_profile_get_created (profile); + if (created == 0) + goto out; + dt = g_date_time_new_from_unix_utc (created); + /* note: this is not shown in the UI, just used for sorting */ + string = g_date_time_format (dt, "%Y%m%d"); +out: + if (dt != NULL) + g_date_time_unref (dt); + return string; +} + +static gchar * +gcm_prefs_get_profile_title (CcColorPanel *prefs, CdProfile *profile) +{ + CdColorspace colorspace; + const gchar *title; + gchar *string; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + g_return_val_if_fail (profile != NULL, NULL); + + string = NULL; + + /* get properties */ + ret = cd_profile_connect_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + + /* add profile description */ + title = cd_profile_get_title (profile); + if (title != NULL) + { + string = g_markup_escape_text (title, -1); + goto out; + } + + /* some meta profiles do not have ICC profiles */ + colorspace = cd_profile_get_colorspace (profile); + if (colorspace == CD_COLORSPACE_RGB) + { + string = g_strdup (C_("Colorspace fallback", "Default RGB")); + goto out; + } + if (colorspace == CD_COLORSPACE_CMYK) + { + string = g_strdup (C_("Colorspace fallback", "Default CMYK")); + goto out; + } + if (colorspace == CD_COLORSPACE_GRAY) + { + string = g_strdup (C_("Colorspace fallback", "Default Gray")); + goto out; + } + + /* fall back to ID, ick */ + string = g_strdup (cd_profile_get_id (profile)); +out: + return string; +} + +static void +gcm_prefs_device_remove_profiles_phase1 (CcColorPanel *prefs, GtkTreeIter *parent) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return; + + /* mark to be removed */ + do { + gtk_tree_store_set (priv->list_store_devices, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, NULL, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_device_remove_profiles_phase2 (CcColorPanel *prefs, GtkTreeIter *parent) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gchar *id_tmp; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return; + + /* remove the other elements */ + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (id_tmp == NULL) + ret = gtk_tree_store_remove (priv->list_store_devices, &iter); + else + ret = gtk_tree_model_iter_next (model, &iter); + g_free (id_tmp); + } while (ret); +} + +static GtkTreeIter * +get_iter_for_profile (GtkTreeModel *model, CdProfile *profile, GtkTreeIter *parent) +{ + const gchar *id; + gboolean ret; + GtkTreeIter iter; + CdProfile *profile_tmp; + + /* get first element */ + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return NULL; + + /* remove the other elements */ + id = cd_profile_get_id (profile); + while (ret) + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile_tmp, + -1); + if (g_strcmp0 (id, cd_profile_get_id (profile_tmp)) == 0) + { + g_object_unref (profile_tmp); + return gtk_tree_iter_copy (&iter); + } + g_object_unref (profile_tmp); + ret = gtk_tree_model_iter_next (model, &iter); + } + + return NULL; +} + +static void +gcm_prefs_device_set_model_by_iter (CcColorPanel *prefs, CdDevice *device, GtkTreeIter *iter) +{ + GString *status = NULL; + const gchar *status_image = NULL; + const gchar *tooltip = NULL; + CdProfile *profile = NULL; + gint age; + GPtrArray *profiles = NULL; + CdProfile *profile_tmp; + guint i; + gchar *title_tmp; + GString *date_tmp; + gchar *sort_tmp; + GtkTreeIter iter_tmp; + GtkTreeIter *iter_tmp_p; + guint threshold = 0; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* set status */ + profile = cd_device_get_default_profile (device); + if (profile == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device is not color managed."); + goto skip; + } + + /* get properties */ + ret = cd_profile_connect_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + +#if CD_CHECK_VERSION(0,1,13) + /* ignore profiles from other user accounts */ + if (!cd_profile_has_access (profile)) + { + /* only print the filename if it exists */ + if (cd_profile_get_filename (profile) != NULL) + { + g_warning ("%s is not usable by this user", + cd_profile_get_filename (profile)); + } + else + { + g_warning ("%s is not usable by this user", + cd_profile_get_id (profile)); + } + goto out; + } +#endif + + /* autogenerated printer defaults */ + if (cd_device_get_kind (device) == CD_DEVICE_KIND_PRINTER && + cd_profile_get_filename (profile) == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device is using manufacturing calibrated data."); + goto skip; + } + + /* autogenerated profiles are crap */ + if (cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE && + !cd_profile_get_has_vcgt (profile)) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device does not have a profile suitable for whole-screen color correction."); + goto skip; + } + + /* yay! */ + status = gcm_prefs_get_profile_age_as_string (profile); + if (status == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + } + + /* greater than the calibration threshold for the device type */ + age = cd_profile_get_age (profile); + age /= 60 * 60 * 24; + if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY) + { + g_settings_get (priv->settings, + GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD, + "u", + &threshold); + } + else if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY) + { + g_settings_get (priv->settings, + GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD, + "u", + &threshold); + } + if (threshold > 0 && age > threshold) + { + status_image = "dialog-warning-symbolic"; + tooltip = _("This device has an old profile that may no longer be accurate."); + } +skip: + /* save to store */ + gtk_tree_store_set (priv->list_store_devices, iter, + GCM_PREFS_COLUMN_STATUS, status->str, + GCM_PREFS_COLUMN_STATUS_IMAGE, status_image, + GCM_PREFS_COLUMN_TOOLTIP, tooltip, + -1); + + /* remove old profiles */ + gcm_prefs_device_remove_profiles_phase1 (prefs, iter); + + /* add profiles */ + profiles = cd_device_get_profiles (device); + if (profiles == NULL) + goto out; + for (i = 0; i < profiles->len; i++) + { + profile_tmp = g_ptr_array_index (profiles, i); + title_tmp = gcm_prefs_get_profile_title (prefs, profile_tmp); + + /* get profile age */ + date_tmp = gcm_prefs_get_profile_age_as_string (profile_tmp); + if (date_tmp == NULL) + { + /* TRANSLATORS: this is when the calibration profile age is not + * specified as it has been autogenerated from the hardware */ + date_tmp = g_string_new (_("Not specified")); + g_string_prepend (date_tmp, ""); + g_string_append (date_tmp, ""); + } + sort_tmp = gcm_prefs_get_profile_created_for_sort (profile_tmp); + + /* get an existing profile, or create a new one */ + iter_tmp_p = get_iter_for_profile (GTK_TREE_MODEL (priv->list_store_devices), + profile_tmp, iter); + if (iter_tmp_p == NULL) + gtk_tree_store_append (priv->list_store_devices, &iter_tmp, iter); + + gtk_tree_store_set (priv->list_store_devices, iter_tmp_p ? iter_tmp_p : &iter_tmp, + GCM_PREFS_COLUMN_DEVICE, device, + GCM_PREFS_COLUMN_PROFILE, profile_tmp, + GCM_PREFS_COLUMN_DEVICE_PATH, cd_device_get_object_path (device), + GCM_PREFS_COLUMN_SORT, sort_tmp, + GCM_PREFS_COLUMN_STATUS, date_tmp->str, + GCM_PREFS_COLUMN_TITLE, title_tmp, + GCM_PREFS_COLUMN_RADIO_VISIBLE, TRUE, + GCM_PREFS_COLUMN_RADIO_ACTIVE, i==0, + -1); + if (iter_tmp_p != NULL) + gtk_tree_iter_free (iter_tmp_p); + g_free (title_tmp); + g_free (sort_tmp); + g_string_free (date_tmp, TRUE); + } + + /* remove old profiles that no longer exist */ + gcm_prefs_device_remove_profiles_phase2 (prefs, iter); +out: + if (status != NULL) + g_string_free (status, TRUE); + if (profiles != NULL) + g_ptr_array_unref (profiles); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_device_changed_cb (CdDevice *device, CcColorPanel *prefs) +{ + const gchar *id; + gboolean ret; + gchar *id_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + id = cd_device_get_object_path (device); + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (g_strcmp0 (id_tmp, id) == 0) + { + /* populate device */ + gcm_prefs_device_set_model_by_iter (prefs, device, &iter); + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device) +{ + gboolean ret; + GError *error = NULL; + CdDeviceKind kind; + const gchar *icon_name; + const gchar *id; + gchar *sort = NULL; + gchar *title = NULL; + GtkTreeIter parent; + CcColorPanelPrivate *priv = prefs->priv; + + + /* get device properties */ + ret = cd_device_connect_sync (device, priv->cancellable, &error); + if (!ret) + { + g_warning ("failed to connect to the device: %s", error->message); + g_error_free (error); + goto out; + } + + /* get icon */ + kind = cd_device_get_kind (device); + icon_name = gcm_prefs_device_kind_to_icon_name (kind); + + /* italic for non-connected devices */ + title = gcm_device_get_title (device); + + /* create sort order */ + sort = g_strdup_printf ("%s%s", + gcm_prefs_device_kind_to_sort (kind), + title); + + /* watch for changes to update the status icons */ + g_signal_connect (device, "changed", + G_CALLBACK (gcm_prefs_device_changed_cb), prefs); + + /* add to list */ + id = cd_device_get_object_path (device); + g_debug ("add %s to device list", id); + gtk_tree_store_append (priv->list_store_devices, &parent, NULL); + gtk_tree_store_set (priv->list_store_devices, &parent, + GCM_PREFS_COLUMN_DEVICE, device, + GCM_PREFS_COLUMN_DEVICE_PATH, id, + GCM_PREFS_COLUMN_SORT, sort, + GCM_PREFS_COLUMN_TITLE, title, + GCM_PREFS_COLUMN_ICON, icon_name, + -1); + gcm_prefs_device_set_model_by_iter (prefs, device, &parent); +out: + g_free (sort); + g_free (title); +} + +static void +gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *cd_device) +{ + GtkTreeIter iter; + GtkTreeModel *model; + const gchar *id; + gchar *id_tmp; + gboolean ret; + CdDevice *device_tmp; + CcColorPanelPrivate *priv = prefs->priv; + + /* remove */ + id = cd_device_get_object_path (cd_device); + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (g_strcmp0 (id_tmp, id) == 0) + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE, &device_tmp, + -1); + g_signal_handlers_disconnect_by_func (device_tmp, + G_CALLBACK (gcm_prefs_device_changed_cb), + prefs); + gtk_tree_store_remove (GTK_TREE_STORE (model), &iter); + g_free (id_tmp); + g_object_unref (device_tmp); + break; + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_update_device_list_extra_entry (CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + gboolean ret; + gchar *id_tmp; + gchar *title = NULL; + GtkTreeIter iter; + + /* select the first device */ + ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter); + if (!ret) + { + /* add the 'No devices detected' entry */ + title = g_strdup_printf ("%s", _("No devices supporting color management detected")); + gtk_tree_store_append (priv->list_store_devices, &iter, NULL); + gtk_tree_store_set (priv->list_store_devices, &iter, + GCM_PREFS_COLUMN_RADIO_VISIBLE, FALSE, + GCM_PREFS_COLUMN_TITLE, title, + -1); + g_free (title); + return; + } + + /* remove the 'No devices detected' entry */ + do + { + gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_devices), &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (id_tmp == NULL) + { + gtk_tree_store_remove (priv->list_store_devices, &iter); + break; + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store_devices), &iter)); +} + +static void +gcm_prefs_device_added_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + /* add the device */ + gcm_prefs_add_device (prefs, device); + + /* ensure we're not showing the 'No devices detected' entry */ + gcm_prefs_update_device_list_extra_entry (prefs); +} + +static void +gcm_prefs_changed_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + g_debug ("changed: %s (doing nothing)", cd_device_get_id (device)); +} + +static void +gcm_prefs_device_removed_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkWidget *widget; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* remove from the UI */ + gcm_prefs_remove_device (prefs, device); + + /* ensure we showing the 'No devices detected' entry if required */ + gcm_prefs_update_device_list_extra_entry (prefs); + + /* select the first device */ + ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter); + if (!ret) + return; + + /* click it */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (priv->list_store_devices)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + gtk_tree_selection_select_iter (selection, &iter); +} + +static gboolean +gcm_prefs_tree_model_count_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + guint *i = (guint *) user_data; + (*i)++; + return FALSE; +} + +static void +gcm_prefs_get_devices_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CcColorPanel *prefs = (CcColorPanel *) user_data; + CdClient *client = CD_CLIENT (object); + CdDevice *device; + GError *error = NULL; + GPtrArray *devices; + GtkTreePath *path; + GtkWidget *widget; + guint i; + guint devices_and_profiles = 0; + CcColorPanelPrivate *priv = prefs->priv; + + /* get devices and add them */ + devices = cd_client_get_devices_finish (client, res, &error); + if (devices == NULL) + { + g_warning ("failed to add connected devices: %s", + error->message); + g_error_free (error); + goto out; + } + for (i = 0; i < devices->len; i++) + { + device = g_ptr_array_index (devices, i); + gcm_prefs_add_device (prefs, device); + } + + /* ensure we show the 'No devices detected' entry if empty */ + gcm_prefs_update_device_list_extra_entry (prefs); + + /* set the cursor on the first device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + path = gtk_tree_path_new_from_string ("0"); + gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); + gtk_tree_path_free (path); + + /* if we have only a few devices and profiles expand the treeview + * devices so they can all be seen */ + gtk_tree_model_foreach (GTK_TREE_MODEL (priv->list_store_devices), + gcm_prefs_tree_model_count_cb, + &devices_and_profiles); + if (devices_and_profiles <= GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED) + gtk_tree_view_expand_all (GTK_TREE_VIEW (widget)); + +out: + if (devices != NULL) + g_ptr_array_unref (devices); +} + +static void +gcm_prefs_button_virtual_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdDeviceKind device_kind; + CdDevice *device; + const gchar *model; + const gchar *manufacturer; + gchar *device_id; + GError *error = NULL; + GHashTable *device_props; + CcColorPanelPrivate *priv = prefs->priv; + + /* get device details */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + device_kind = gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + 2; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_model")); + model = gtk_entry_get_text (GTK_ENTRY (widget)); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_manufacturer")); + manufacturer = gtk_entry_get_text (GTK_ENTRY (widget)); + + /* create device */ + device_id = g_strdup_printf ("%s-%s-%s", + cd_device_kind_to_string (device_kind), + manufacturer, + model); + device_props = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_insert (device_props, + g_strdup ("Kind"), + g_strdup (cd_device_kind_to_string (device_kind))); + g_hash_table_insert (device_props, + g_strdup ("Mode"), + g_strdup (cd_device_mode_to_string (CD_DEVICE_MODE_VIRTUAL))); + g_hash_table_insert (device_props, + g_strdup ("Colorspace"), + g_strdup (cd_colorspace_to_string (CD_COLORSPACE_RGB))); + g_hash_table_insert (device_props, + g_strdup ("Model"), + g_strdup (model)); + g_hash_table_insert (device_props, + g_strdup ("Vendor"), + g_strdup (manufacturer)); + device = cd_client_create_device_sync (priv->client, + device_id, + CD_OBJECT_SCOPE_DISK, + device_props, + priv->cancellable, + &error); + if (device == NULL) + { + g_warning ("Failed to add create virtual device: %s", + error->message); + g_error_free (error); + goto out; + } +out: + g_hash_table_unref (device_props); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_hide (widget); + g_free (device_id); +} + +static void +gcm_prefs_button_virtual_cancel_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_hide (widget); +} + +static gboolean +gcm_prefs_virtual_delete_event_cb (GtkWidget *widget, + GdkEvent *event, + CcColorPanel *prefs) +{ + gcm_prefs_button_virtual_cancel_cb (widget, prefs); + return TRUE; +} + +static const gchar * +cd_device_kind_to_localised_string (CdDeviceKind device_kind) +{ + if (device_kind == CD_DEVICE_KIND_DISPLAY) + return C_("Device kind", "Display"); + if (device_kind == CD_DEVICE_KIND_SCANNER) + return C_("Device kind", "Scanner"); + if (device_kind == CD_DEVICE_KIND_PRINTER) + return C_("Device kind", "Printer"); + if (device_kind == CD_DEVICE_KIND_CAMERA) + return C_("Device kind", "Camera"); + if (device_kind == CD_DEVICE_KIND_WEBCAM) + return C_("Device kind", "Webcam"); + return NULL; +} + +static void +gcm_prefs_setup_virtual_combobox (GtkWidget *widget) +{ + guint i; + const gchar *text; + + for (i=CD_DEVICE_KIND_SCANNER; ipriv; + + ret = cd_client_connect_finish (priv->client, + res, + &error); + if (!ret) + { + g_warning ("failed to connect to colord: %s", error->message); + g_error_free (error); + return; + } + + /* set calibrate button sensitivity */ + gcm_prefs_sensor_coldplug (prefs); + + + /* get devices */ + cd_client_get_devices (priv->client, + priv->cancellable, + gcm_prefs_get_devices_cb, + prefs); +} + +static void +gcm_prefs_window_realize_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + prefs->priv->main_window = gtk_widget_get_toplevel (widget); +} + +static const char * +cc_color_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/color"; +} + +static void +cc_color_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_dispose (GObject *object) +{ + CcColorPanelPrivate *priv = CC_COLOR_PANEL (object)->priv; + + if (priv->settings) + { + g_object_unref (priv->settings); + priv->settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->client != NULL) + { + g_object_unref (priv->client); + priv->client = NULL; + } + if (priv->current_device != NULL) + { + g_object_unref (priv->current_device); + priv->current_device = NULL; + } + if (priv->sensor != NULL) + { + g_object_unref (priv->sensor); + priv->sensor = NULL; + } + + G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object); +} + +static void +cc_color_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object); +} + +static void +cc_color_panel_class_init (CcColorPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcColorPanelPrivate)); + + panel_class->get_help_uri = cc_color_panel_get_help_uri; + + object_class->get_property = cc_color_panel_get_property; + object_class->set_property = cc_color_panel_set_property; + object_class->dispose = cc_color_panel_dispose; + object_class->finalize = cc_color_panel_finalize; +} + +static void +cc_color_panel_init (CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv; + GError *error = NULL; + GtkStyleContext *context; + GtkTreeSelection *selection; + GtkWidget *widget; + + priv = prefs->priv = COLOR_PANEL_PRIVATE (prefs); + + priv->builder = gtk_builder_new (); + gtk_builder_add_from_file (priv->builder, + GNOMECC_UI_DIR "/color.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + priv->cancellable = g_cancellable_new (); + + /* setup defaults */ + priv->settings = g_settings_new (GCM_SETTINGS_SCHEMA); + + /* create list stores */ + priv->list_store_devices = gtk_tree_store_new (GCM_PREFS_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + CD_TYPE_DEVICE, + CD_TYPE_PROFILE, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + + /* assign buttons */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_add_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_remove_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_view_cb), prefs); + + /* create device tree view */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (priv->list_store_devices)); + gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (widget), TRUE); + gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (widget), 0); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + g_signal_connect (selection, "changed", + G_CALLBACK (gcm_prefs_devices_treeview_clicked_cb), + prefs); + g_signal_connect (GTK_TREE_VIEW (widget), "row-activated", + G_CALLBACK (gcm_prefs_treeview_row_activated_cb), + prefs); + g_signal_connect (GTK_TREE_VIEW (widget), "popup-menu", + G_CALLBACK (gcm_prefs_treeview_popup_menu_cb), + prefs); + + /* add columns to the tree view */ + gcm_prefs_add_devices_columns (prefs, GTK_TREE_VIEW (widget)); + + /* force to be at least ~6 rows high */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "scrolledwindow_devices")); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), + 200); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_default")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_default_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_delete_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_device_add_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_calibrate_cb), prefs); + + /* make devices toolbar sexy */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "scrolledwindow_devices")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbar_devices")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + /* set up virtual dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gcm_prefs_virtual_delete_event_cb), + prefs); + g_signal_connect (widget, "drag-data-received", + G_CALLBACK (gcm_prefs_virtual_drag_data_received_cb), + prefs); + gcm_prefs_setup_drag_and_drop (widget); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_virtual_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_virtual_add_cb), + prefs); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_virtual_cancel")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_virtual_cancel_cb), + prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + gcm_prefs_setup_virtual_combobox (widget); + + /* set up assign dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gcm_prefs_profile_delete_event_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_assign_cancel")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_assign_cancel_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_assign_ok")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs); + + /* setup icc profiles list */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + gcm_prefs_set_combo_simple_text (widget); + gtk_widget_set_sensitive (widget, FALSE); + g_signal_connect (G_OBJECT (widget), "changed", + G_CALLBACK (gcm_prefs_profile_combo_changed_cb), prefs); + + /* use a device client array */ + priv->client = cd_client_new (); + g_signal_connect (priv->client, "device-added", + G_CALLBACK (gcm_prefs_device_added_cb), prefs); + g_signal_connect (priv->client, "device-removed", + G_CALLBACK (gcm_prefs_device_removed_cb), prefs); + g_signal_connect (priv->client, "changed", + G_CALLBACK (gcm_prefs_changed_cb), prefs); + + /* connect to colord */ + cd_client_connect (priv->client, + priv->cancellable, + gcm_prefs_connect_cb, + prefs); + + /* use the color sensor */ + g_signal_connect (priv->client, "sensor-added", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs); + g_signal_connect (priv->client, "sensor-removed", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs); + + /* set calibrate button sensitivity */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); + + widget = WID (priv->builder, "dialog-vbox1"); + gtk_widget_reparent (widget, (GtkWidget *) prefs); + g_signal_connect (widget, "realize", + G_CALLBACK (gcm_prefs_window_realize_cb), + prefs); +} + +void +cc_color_panel_register (GIOModule *module) +{ + cc_color_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_COLOR_PANEL, + "color", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/datetime/cc-datetime-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/datetime/cc-datetime-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/datetime/cc-datetime-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/datetime/cc-datetime-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2010 Intel, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Thomas Wood + * + */ + +#include "config.h" +#include "cc-datetime-panel.h" + +#include +#include "cc-timezone-map.h" +#include "timedated.h" +#include "date-endian.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API + +#include +#include +#include +#include + +#include +#include + +/* FIXME: This should be "Etc/GMT" instead */ +#define DEFAULT_TZ "Europe/London" +#define GETTEXT_PACKAGE_TIMEZONES GETTEXT_PACKAGE "-timezones" + +CC_PANEL_REGISTER (CcDateTimePanel, cc_date_time_panel) + +#define DATE_TIME_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DATE_TIME_PANEL, CcDateTimePanelPrivate)) + +enum { + CITY_COL_CITY, + CITY_COL_REGION, + CITY_COL_CITY_TRANSLATED, + CITY_COL_REGION_TRANSLATED, + CITY_COL_ZONE, + CITY_NUM_COLS +}; + +enum { + REGION_COL_REGION, + REGION_COL_REGION_TRANSLATED, + REGION_NUM_COLS +}; + +#define W(x) (GtkWidget*) gtk_builder_get_object (priv->builder, x) + +#define CLOCK_SCHEMA "org.gnome.desktop.interface" +#define CLOCK_FORMAT_KEY "clock-format" + +struct _CcDateTimePanelPrivate +{ + GtkBuilder *builder; + GtkWidget *map; + + TzLocation *current_location; + + GtkTreeModel *locations; + GtkTreeModelFilter *city_filter; + + GDateTime *date; + + GSettings *settings; + GDesktopClockFormat clock_format; + + GnomeWallClock *clock_tracker; + + Timedate1 *dtm; + GCancellable *cancellable; + + GPermission *permission; +}; + +static void update_time (CcDateTimePanel *self); + +static void +cc_date_time_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_date_time_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_date_time_panel_dispose (GObject *object) +{ + CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (object)->priv; + + if (priv->clock_tracker != NULL) + { + g_object_unref (priv->clock_tracker); + priv->clock_tracker = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->settings) + { + g_object_unref (priv->settings); + priv->settings = NULL; + } + + if (priv->date) + { + g_date_time_unref (priv->date); + priv->date = NULL; + } + + if (priv->cancellable) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + if (priv->dtm) + { + g_object_unref (priv->dtm); + priv->dtm = NULL; + } + + if (priv->permission) + { + g_object_unref (priv->permission); + priv->permission = NULL; + } + + G_OBJECT_CLASS (cc_date_time_panel_parent_class)->dispose (object); +} + +static GPermission * +cc_date_time_panel_get_permission (CcPanel *panel) +{ + CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (panel)->priv; + + return priv->permission; +} + +static const char * +cc_date_time_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/clock"; +} + +static void +cc_date_time_panel_class_init (CcDateTimePanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcDateTimePanelPrivate)); + + object_class->get_property = cc_date_time_panel_get_property; + object_class->set_property = cc_date_time_panel_set_property; + object_class->dispose = cc_date_time_panel_dispose; + + panel_class->get_permission = cc_date_time_panel_get_permission; + panel_class->get_help_uri = cc_date_time_panel_get_help_uri; +} + +static void clock_settings_changed_cb (GSettings *settings, + gchar *key, + CcDateTimePanel *panel); + +static void +change_clock_settings (GObject *gobject, + GParamSpec *pspec, + CcDateTimePanel *panel) +{ + CcDateTimePanelPrivate *priv = panel->priv; + GDesktopClockFormat value; + + g_signal_handlers_block_by_func (priv->settings, clock_settings_changed_cb, + panel); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W ("24h_button")))) + value = G_DESKTOP_CLOCK_FORMAT_24H; + else + value = G_DESKTOP_CLOCK_FORMAT_12H; + + g_settings_set_enum (priv->settings, CLOCK_FORMAT_KEY, value); + priv->clock_format = value; + + update_time (panel); + + g_signal_handlers_unblock_by_func (priv->settings, clock_settings_changed_cb, + panel); +} + +static void +clock_settings_changed_cb (GSettings *settings, + gchar *key, + CcDateTimePanel *panel) +{ + CcDateTimePanelPrivate *priv = panel->priv; + GtkWidget *button24h; + GtkWidget *button12h; + GDesktopClockFormat value; + + value = g_settings_get_enum (settings, CLOCK_FORMAT_KEY); + priv->clock_format = value; + + button24h = W ("24h_button"); + button12h = W ("12h_button"); + + g_signal_handlers_block_by_func (button24h, change_clock_settings, panel); + + if (value == G_DESKTOP_CLOCK_FORMAT_24H) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button24h), TRUE); + else + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button12h), TRUE); + + update_time (panel); + + g_signal_handlers_unblock_by_func (button24h, change_clock_settings, panel); +} + +static void +update_time (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + char *label; + char *am_pm_widgets[] = {"ampm_up_button", "ampm_down_button", "ampm_label" }; + guint i; + + if (priv->clock_format == G_DESKTOP_CLOCK_FORMAT_24H) + { + /* Update the hours label */ + label = g_date_time_format (priv->date, "%H"); + gtk_label_set_text (GTK_LABEL (W("hours_label")), label); + g_free (label); + } + else + { + /* Update the hours label */ + label = g_date_time_format (priv->date, "%I"); + gtk_label_set_text (GTK_LABEL (W("hours_label")), label); + g_free (label); + + /* Set AM/PM */ + label = g_date_time_format (priv->date, "%p"); + gtk_label_set_text (GTK_LABEL (W("ampm_label")), label); + g_free (label); + } + + for (i = 0; i < G_N_ELEMENTS (am_pm_widgets); i++) + gtk_widget_set_visible (W(am_pm_widgets[i]), + priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H); + + /* Update the minutes label */ + label = g_date_time_format (priv->date, "%M"); + gtk_label_set_text (GTK_LABEL (W("minutes_label")), label); + g_free (label); +} + +static void +set_time_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CcDateTimePanel *self = user_data; + GError *error; + + error = NULL; + if (!timedate1_call_set_time_finish (self->priv->dtm, + res, + &error)) + { + /* TODO: display any error in a user friendly way */ + g_warning ("Could not set system time: %s", error->message); + g_error_free (error); + } + else + { + update_time (self); + } +} + +static void +set_timezone_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CcDateTimePanel *self = user_data; + GError *error; + + error = NULL; + if (!timedate1_call_set_timezone_finish (self->priv->dtm, + res, + &error)) + { + /* TODO: display any error in a user friendly way */ + g_warning ("Could not set system timezone: %s", error->message); + g_error_free (error); + } +} + +static void +set_using_ntp_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CcDateTimePanel *self = user_data; + GError *error; + + error = NULL; + if (!timedate1_call_set_ntp_finish (self->priv->dtm, + res, + &error)) + { + /* TODO: display any error in a user friendly way */ + g_warning ("Could not set system to use NTP: %s", error->message); + g_error_free (error); + } +} + +static void +queue_set_datetime (CcDateTimePanel *self) +{ + gint64 unixtime; + + /* timedated expects number of microseconds since 1 Jan 1970 UTC */ + unixtime = g_date_time_to_unix (self->priv->date); + + timedate1_call_set_time (self->priv->dtm, + unixtime * 1000000, + FALSE, + TRUE, + self->priv->cancellable, + set_time_cb, + self); +} + +static void +queue_set_ntp (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + gboolean using_ntp; + /* for now just do it */ + using_ntp = gtk_switch_get_active (GTK_SWITCH (W("network_time_switch"))); + + timedate1_call_set_ntp (self->priv->dtm, + using_ntp, + TRUE, + self->priv->cancellable, + set_using_ntp_cb, + self); +} + +static void +queue_set_timezone (CcDateTimePanel *self) +{ + /* for now just do it */ + if (self->priv->current_location) + { + timedate1_call_set_timezone (self->priv->dtm, + self->priv->current_location->zone, + TRUE, + self->priv->cancellable, + set_timezone_cb, + self); + } +} + +static void +change_date (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + guint mon, y, d; + GDateTime *old_date; + + old_date = priv->date; + + mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox"))); + y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton"))); + d = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("day-spinbutton"))); + + priv->date = g_date_time_new_local (y, mon, d, + g_date_time_get_hour (old_date), + g_date_time_get_minute (old_date), + g_date_time_get_second (old_date)); + g_date_time_unref (old_date); + queue_set_datetime (self); +} + +static void +region_changed_cb (GtkComboBox *box, + CcDateTimePanel *self) +{ + GtkTreeModelFilter *modelfilter; + + modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (self->priv->builder, "city-modelfilter")); + + gtk_tree_model_filter_refilter (modelfilter); +} + +static void +city_changed_cb (GtkComboBox *box, + CcDateTimePanel *self) +{ + static gboolean inside = FALSE; + GtkTreeIter iter; + gchar *zone; + + /* prevent re-entry from location changed callback */ + if (inside) + return; + + inside = TRUE; + + if (gtk_combo_box_get_active_iter (box, &iter)) + { + gtk_tree_model_get (gtk_combo_box_get_model (box), &iter, + CITY_COL_ZONE, &zone, -1); + + cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), zone); + + g_free (zone); + } + + inside = FALSE; +} + +static void +update_timezone (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + GtkWidget *widget; + gchar **split; + GtkTreeIter iter; + GtkTreeModel *model; + + /* tz.c updates the local timezone, which means the spin buttons can be + * updated with the current time of the new location */ + + split = g_strsplit (priv->current_location->zone, "/", 2); + + /* remove underscores */ + g_strdelimit (split[1], "_", ' '); + + /* update region combo */ + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, + "region_combobox"); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + gtk_tree_model_get_iter_first (model, &iter); + + do + { + gchar *string; + + gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1); + + if (!g_strcmp0 (string, split[0])) + { + g_free (string); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + break; + } + g_free (string); + } + while (gtk_tree_model_iter_next (model, &iter)); + + + /* update city combo */ + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, + "city_combobox"); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + gtk_tree_model_filter_refilter ((GtkTreeModelFilter *) gtk_builder_get_object (priv->builder, "city-modelfilter")); + gtk_tree_model_get_iter_first (model, &iter); + + do + { + gchar *string; + + gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1); + + if (!g_strcmp0 (string, split[1])) + { + g_free (string); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + break; + } + g_free (string); + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_strfreev (split); +} + +static void +location_changed_cb (CcTimezoneMap *map, + TzLocation *location, + CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + GtkWidget *region_combo, *city_combo; + + g_debug ("location changed to %s/%s", location->country, location->zone); + + self->priv->current_location = location; + + /* Update the combo boxes */ + region_combo = W("region_combobox"); + city_combo = W("city_combobox"); + + g_signal_handlers_block_by_func (region_combo, region_changed_cb, self); + g_signal_handlers_block_by_func (city_combo, city_changed_cb, self); + + update_timezone (self); + + g_signal_handlers_unblock_by_func (region_combo, region_changed_cb, self); + g_signal_handlers_unblock_by_func (city_combo, city_changed_cb, self); + + queue_set_timezone (self); +} + +static void +get_initial_timezone (CcDateTimePanel *self) +{ + const gchar *timezone; + + if (self->priv->dtm) + timezone = timedate1_get_timezone (self->priv->dtm); + else + timezone = NULL; + + if (timezone == NULL || + !cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), timezone)) + { + g_warning ("Timezone '%s' is unhandled, setting %s as default", timezone ? timezone : "(null)", DEFAULT_TZ); + cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), DEFAULT_TZ); + } + self->priv->current_location = cc_timezone_map_get_location (CC_TIMEZONE_MAP (self->priv->map)); + update_timezone (self); +} + +/* load region and city tree models */ +struct get_region_data +{ + GtkListStore *region_store; + GtkListStore *city_store; + GHashTable *table; +}; + +/* Slash look-alikes that might be used in translations */ +#define TRANSLATION_SPLIT \ + "\342\201\204" /* FRACTION SLASH */ \ + "\342\210\225" /* DIVISION SLASH */ \ + "\342\247\270" /* BIG SOLIDUS */ \ + "\357\274\217" /* FULLWIDTH SOLIDUS */ \ + "/" + +static void +get_regions (TzLocation *loc, + struct get_region_data *data) +{ + gchar *zone; + gchar **split; + gchar **split_translated; + gchar *translated_city; + + zone = g_strdup (loc->zone); + g_strdelimit (zone, "_", ' '); + split = g_strsplit (zone, "/", 2); + g_free (zone); + + /* Load the translation for it */ + zone = g_strdup (dgettext (GETTEXT_PACKAGE_TIMEZONES, loc->zone)); + g_strdelimit (zone, "_", ' '); + split_translated = g_regex_split_simple ("[\\x{2044}\\x{2215}\\x{29f8}\\x{ff0f}/]", zone, 0, 0); + g_free (zone); + + if (!g_hash_table_lookup_extended (data->table, split[0], NULL, NULL)) + { + g_hash_table_insert (data->table, g_strdup (split[0]), + GINT_TO_POINTER (1)); + gtk_list_store_insert_with_values (data->region_store, NULL, 0, + REGION_COL_REGION, split[0], + REGION_COL_REGION_TRANSLATED, split_translated[0], -1); + } + + /* g_regex_split_simple() splits too much for us, and would break + * America/Argentina/Buenos_Aires into 3 strings, so rejoin the city part */ + translated_city = g_strjoinv ("/", split_translated + 1); + + gtk_list_store_insert_with_values (data->city_store, NULL, 0, + CITY_COL_CITY, split[1], + CITY_COL_CITY_TRANSLATED, translated_city, + CITY_COL_REGION, split[0], + CITY_COL_REGION_TRANSLATED, split_translated[0], + CITY_COL_ZONE, loc->zone, + -1); + + g_free (translated_city); + g_strfreev (split); + g_strfreev (split_translated); +} + +static gboolean +city_model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GtkComboBox *combo) +{ + GtkTreeModel *combo_model; + GtkTreeIter combo_iter; + gchar *active_region = NULL; + gchar *city_region = NULL; + gboolean result; + + if (gtk_combo_box_get_active_iter (combo, &combo_iter) == FALSE) + return FALSE; + + combo_model = gtk_combo_box_get_model (combo); + gtk_tree_model_get (combo_model, &combo_iter, + CITY_COL_CITY, &active_region, -1); + + gtk_tree_model_get (model, iter, + CITY_COL_REGION, &city_region, -1); + + if (g_strcmp0 (active_region, city_region) == 0) + result = TRUE; + else + result = FALSE; + + g_free (city_region); + + g_free (active_region); + + return result; +} + + +static void +load_regions_model (GtkListStore *regions, GtkListStore *cities) +{ + struct get_region_data data; + TzDB *db; + GHashTable *table; + + + db = tz_load_db (); + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + data.table = table; + data.region_store = regions; + data.city_store = cities; + + g_ptr_array_foreach (db->locations, (GFunc) get_regions, &data); + + g_hash_table_destroy (table); + + tz_db_free (db); + + /* sort the models */ + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (regions), + REGION_COL_REGION_TRANSLATED, + GTK_SORT_ASCENDING); +} + +static void +update_widget_state_for_ntp (CcDateTimePanel *panel, + gboolean using_ntp) +{ + CcDateTimePanelPrivate *priv = panel->priv; + gboolean allowed; + + /* need to check polkit before revealing to user */ + allowed = (! priv->permission || g_permission_get_allowed (priv->permission)); + + gtk_widget_set_sensitive (W("table1"), !using_ntp && allowed); + gtk_widget_set_sensitive (W("table2"), !using_ntp && allowed); +} + +static void +day_changed (GtkWidget *widget, + CcDateTimePanel *panel) +{ + change_date (panel); +} + +static void +month_year_changed (GtkWidget *widget, + CcDateTimePanel *panel) +{ + CcDateTimePanelPrivate *priv = panel->priv; + guint mon, y; + guint num_days; + GtkAdjustment *adj; + GtkSpinButton *day_spin; + + mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox"))); + y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton"))); + + /* Check the number of days in that month */ + num_days = g_date_get_days_in_month (mon, y); + + day_spin = GTK_SPIN_BUTTON (W("day-spinbutton")); + adj = GTK_ADJUSTMENT (gtk_spin_button_get_adjustment (day_spin)); + gtk_adjustment_set_upper (adj, num_days + 1); + + if (gtk_spin_button_get_value_as_int (day_spin) > num_days) + gtk_spin_button_set_value (day_spin, num_days); + + change_date (panel); +} + +static void +on_clock_changed (GnomeWallClock *clock, + GParamSpec *pspec, + CcDateTimePanel *panel) +{ + CcDateTimePanelPrivate *priv = panel->priv; + + g_date_time_unref (priv->date); + priv->date = g_date_time_new_now_local (); + update_time (panel); +} + +static void +change_time (GtkButton *button, + CcDateTimePanel *panel) +{ + CcDateTimePanelPrivate *priv = panel->priv; + const gchar *widget_name; + gint direction; + GDateTime *old_date; + + old_date = priv->date; + + widget_name = gtk_buildable_get_name (GTK_BUILDABLE (button)); + + if (strstr (widget_name, "up")) + direction = 1; + else + direction = -1; + + if (widget_name[0] == 'h') + { + priv->date = g_date_time_add_hours (old_date, direction); + } + else if (widget_name[0] == 'm') + { + priv->date = g_date_time_add_minutes (old_date, direction); + } + else + { + int hour; + hour = g_date_time_get_hour (old_date); + if (hour >= 12) + priv->date = g_date_time_add_hours (old_date, -12); + else + priv->date = g_date_time_add_hours (old_date, 12); + } + g_date_time_unref (old_date); + + update_time (panel); + queue_set_datetime (panel); +} + +static void +change_ntp (GObject *gobject, + GParamSpec *pspec, + CcDateTimePanel *self) +{ + update_widget_state_for_ntp (self, gtk_switch_get_active (GTK_SWITCH (gobject))); + queue_set_ntp (self); +} + +static void +on_permission_changed (GPermission *permission, + GParamSpec *pspec, + gpointer data) +{ + CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (data)->priv; + gboolean allowed, using_ntp; + + allowed = g_permission_get_allowed (permission); + using_ntp = gtk_switch_get_active (GTK_SWITCH (W("network_time_switch"))); + + /* All the widgets but the lock button and the 24h setting */ + gtk_widget_set_sensitive (W("map-vbox"), allowed); + gtk_widget_set_sensitive (W("hbox2"), allowed); + gtk_widget_set_sensitive (W("alignment2"), allowed); + update_widget_state_for_ntp (data, using_ntp); +} + +static void +update_ntp_switch_from_system (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + gboolean using_ntp; + GtkWidget *switch_widget; + + using_ntp = timedate1_get_ntp (self->priv->dtm); + + switch_widget = W("network_time_switch"); + g_signal_handlers_block_by_func (switch_widget, change_ntp, self); + gtk_switch_set_active (GTK_SWITCH (switch_widget), using_ntp); + update_widget_state_for_ntp (self, using_ntp); + g_signal_handlers_unblock_by_func (switch_widget, change_ntp, self); +} + +static void +on_ntp_changed (CcDateTimePanel *self) +{ + update_ntp_switch_from_system (self); +} + +static void +on_timezone_changed (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv = self->priv; + GtkWidget *region_combo, *city_combo; + + region_combo = W("region_combobox"); + city_combo = W("city_combobox"); + + g_signal_handlers_block_by_func (region_combo, region_changed_cb, self); + g_signal_handlers_block_by_func (city_combo, city_changed_cb, self); + g_signal_handlers_block_by_func (self->priv->map, location_changed_cb, self); + + get_initial_timezone (self); + + g_signal_handlers_unblock_by_func (region_combo, region_changed_cb, self); + g_signal_handlers_unblock_by_func (city_combo, city_changed_cb, self); + g_signal_handlers_unblock_by_func (self->priv->map, location_changed_cb, self); +} + +static void +on_timedated_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + const gchar **invalidated_properties, + CcDateTimePanel *self) +{ + GError *error; + GVariant *variant; + GVariant *v; + guint i; + + if (invalidated_properties != NULL) + for (i = 0; invalidated_properties[i] != NULL; i++) { + error = NULL; + /* See https://bugs.freedesktop.org/show_bug.cgi?id=37632 for the reason why we're doing this */ + variant = g_dbus_proxy_call_sync (proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", "org.freedesktop.timedate1", invalidated_properties[i]), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) { + g_warning ("Failed to get property '%s': %s", invalidated_properties[i], error->message); + g_error_free (error); + } else { + g_variant_get (variant, "(v)", &v); + g_dbus_proxy_set_cached_property (proxy, invalidated_properties[i], v); + g_variant_unref (variant); + } + } +} + +static void +reorder_date_widget (DateEndianess endianess, + CcDateTimePanelPrivate *priv) +{ + GtkWidget *month, *day, *year; + GtkBox *box; + + if (endianess == DATE_ENDIANESS_MIDDLE) + return; + + month = W ("month-combobox"); + day = W ("day-spinbutton"); + year = W("year-spinbutton"); + + box = GTK_BOX (W("table1")); + + switch (endianess) { + case DATE_ENDIANESS_LITTLE: + gtk_box_reorder_child (box, month, 0); + gtk_box_reorder_child (box, day, 0); + gtk_box_reorder_child (box, year, -1); + break; + case DATE_ENDIANESS_BIG: + gtk_box_reorder_child (box, month, 0); + gtk_box_reorder_child (box, year, 0); + gtk_box_reorder_child (box, day, -1); + break; + case DATE_ENDIANESS_MIDDLE: + /* Let's please GCC */ + g_assert_not_reached (); + break; + } +} + +static void +cc_date_time_panel_init (CcDateTimePanel *self) +{ + CcDateTimePanelPrivate *priv; + gchar *objects[] = { "datetime-panel", "region-liststore", "city-liststore", + "month-liststore", "city-modelfilter", "city-modelsort", NULL }; + char *buttons[] = { "hour_up_button", "hour_down_button", "min_up_button", + "min_down_button", "ampm_up_button", "ampm_down_button" }; + GtkWidget *widget; + GtkAdjustment *adjustment; + GError *err = NULL; + GtkTreeModelFilter *city_modelfilter; + GtkTreeModelSort *city_modelsort; + guint i, num_days; + int ret; + DateEndianess endianess; + GError *error; + + priv = self->priv = DATE_TIME_PANEL_PRIVATE (self); + + priv->cancellable = g_cancellable_new (); + error = NULL; + priv->dtm = timedate1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + priv->cancellable, + &error); + if (priv->dtm == NULL) { + g_warning ("could not get proxy for DateTimeMechanism: %s", error->message); + g_error_free (error); + } + + priv->builder = gtk_builder_new (); + + ret = gtk_builder_add_objects_from_file (priv->builder, DATADIR"/datetime.ui", + objects, &err); + + if (ret == 0) + { + g_warning ("Could not load ui: %s", err ? err->message : "No reason"); + if (err) + g_error_free (err); + return; + } + + /* set up network time button */ + if (priv->dtm != NULL) + update_ntp_switch_from_system (self); + g_signal_connect (W("network_time_switch"), "notify::active", + G_CALLBACK (change_ntp), self); + + /* set up time editing widgets */ + for (i = 0; i < G_N_ELEMENTS (buttons); i++) + { + g_signal_connect (W(buttons[i]), "clicked", + G_CALLBACK (change_time), self); + } + + /* set up date editing widgets */ + priv->date = g_date_time_new_now_local (); + endianess = date_endian_get_default (FALSE); + reorder_date_widget (endianess, priv); + + /* Force the direction for the time, so that the time + * is presented correctly for RTL languages */ + gtk_widget_set_direction (W("table2"), GTK_TEXT_DIR_LTR); + + gtk_combo_box_set_active (GTK_COMBO_BOX (W ("month-combobox")), + g_date_time_get_month (priv->date) - 1); + g_signal_connect (G_OBJECT (W("month-combobox")), "changed", + G_CALLBACK (month_year_changed), self); + + num_days = g_date_get_days_in_month (g_date_time_get_month (priv->date), + g_date_time_get_year (priv->date)); + adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_day_of_month (priv->date), 1, + num_days + 1, 1, 10, 1); + gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("day-spinbutton")), + adjustment); + g_signal_connect (G_OBJECT (W("day-spinbutton")), "value-changed", + G_CALLBACK (day_changed), self); + + adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_year (priv->date), + G_MINDOUBLE, G_MAXDOUBLE, 1, + 10, 1); + gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("year-spinbutton")), + adjustment); + g_signal_connect (G_OBJECT (W("year-spinbutton")), "value-changed", + G_CALLBACK (month_year_changed), self); + + /* set up timezone map */ + priv->map = widget = (GtkWidget *) cc_timezone_map_new (); + gtk_widget_show (widget); + + gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (priv->builder, + "aspectmap")), + widget); + + gtk_container_add (GTK_CONTAINER (self), + GTK_WIDGET (gtk_builder_get_object (priv->builder, + "datetime-panel"))); + + + /* setup the time itself */ + priv->clock_tracker = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL); + g_signal_connect (priv->clock_tracker, "notify::clock", G_CALLBACK (on_clock_changed), self); + + priv->settings = g_settings_new (CLOCK_SCHEMA); + clock_settings_changed_cb (priv->settings, CLOCK_FORMAT_KEY, self); + g_signal_connect (priv->settings, "changed::" CLOCK_FORMAT_KEY, + G_CALLBACK (clock_settings_changed_cb), self); + + g_signal_connect (W("24h_button"), "notify::active", + G_CALLBACK (change_clock_settings), self); + + update_time (self); + + priv->locations = (GtkTreeModel*) gtk_builder_get_object (priv->builder, + "region-liststore"); + + load_regions_model (GTK_LIST_STORE (priv->locations), + GTK_LIST_STORE (gtk_builder_get_object (priv->builder, + "city-liststore"))); + + city_modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (priv->builder, "city-modelfilter")); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, + "region_combobox"); + city_modelsort = GTK_TREE_MODEL_SORT (gtk_builder_get_object (priv->builder, "city-modelsort")); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (city_modelsort), CITY_COL_CITY_TRANSLATED, + GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (city_modelfilter, + (GtkTreeModelFilterVisibleFunc) city_model_filter_func, + widget, + NULL); + + /* After the initial setup, so we can be sure that + * the model is filled up */ + get_initial_timezone (self); + + widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder, + "region_combobox"); + g_signal_connect (widget, "changed", G_CALLBACK (region_changed_cb), self); + + widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder, + "city_combobox"); + g_signal_connect (widget, "changed", G_CALLBACK (city_changed_cb), self); + + g_signal_connect (self->priv->map, "location-changed", + G_CALLBACK (location_changed_cb), self); + + /* Watch changes of timedated remote service properties */ + if (priv->dtm) + { + g_signal_connect (priv->dtm, "g-properties-changed", + G_CALLBACK (on_timedated_properties_changed), self); + g_signal_connect_swapped (priv->dtm, "notify::ntp", + G_CALLBACK (on_ntp_changed), self); + g_signal_connect_swapped (priv->dtm, "notify::timezone", + G_CALLBACK (on_timezone_changed), self); + } + /* We ignore UTC <--> LocalRTC changes at the moment */ + + /* add the lock button */ + priv->permission = polkit_permission_new_sync ("org.gnome.controlcenter.datetime.configure", NULL, NULL, NULL); + if (priv->permission == NULL) + { + g_warning ("Your system does not have the '%s' PolicyKit files installed. Please check your installation", + "org.gnome.controlcenter.datetime.configure"); + return; + } + + g_signal_connect (priv->permission, "notify", + G_CALLBACK (on_permission_changed), self); + on_permission_changed (priv->permission, NULL, self); +} + +void +cc_date_time_panel_register (GIOModule *module) +{ + bind_textdomain_codeset (GETTEXT_PACKAGE_TIMEZONES, "UTF-8"); + + cc_date_time_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_DATE_TIME_PANEL, + "datetime", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/display/cc-display-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/display/cc-display-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/display/cc-display-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/display/cc-display-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2983 @@ +/* + * Copyright (C) 2007, 2008 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Soren Sandmann + * + */ + +#include +#include +#include +#include + +#include "cc-display-panel.h" + +#include +#include "scrollarea.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include +#include +#include +#include +#include +#include + +CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) + +#define DISPLAY_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DISPLAY_PANEL, CcDisplayPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +#define TOP_BAR_HEIGHT 10 + +#define CLOCK_SCHEMA "org.gnome.desktop.interface" +#define CLOCK_FORMAT_KEY "clock-format" + +/* The minimum supported size for the panel, see: + * http://live.gnome.org/Design/SystemSettings */ +#define MINIMUM_WIDTH 675 +#define MINIMUM_HEIGHT 530 + +#define UNITY_GSETTINGS_SCHEMA "org.compiz.unityshell" +#define UNITY_GSETTINGS_PATH "/org/compiz/profiles/unity/plugins/unityshell/" +#define UNITY_LAUNCHER_ALL_MONITORS_KEY "num-launchers" +#define UNITY_STICKY_EDGE_KEY "launcher-capture-mouse" +#define UNITY2D_GSETTINGS_MAIN "com.canonical.Unity2d" +#define UNITY2D_GSETTINGS_LAUNCHER "com.canonical.Unity2d.Launcher" + +enum { + TEXT_COL, + WIDTH_COL, + HEIGHT_COL, + RATE_COL, + SORT_COL, + ROTATION_COL, + NUM_COLS +}; + +struct _CcDisplayPanelPrivate +{ + GnomeRRScreen *screen; + GnomeRRConfig *current_configuration; + GnomeRRLabeler *labeler; + GnomeRROutputInfo *current_output; + + GSettings *clock_settings; + GSettings *unity_settings; + GSettings *unity2d_settings_main; + GSettings *unity2d_settings_launcher; + GtkBuilder *builder; + guint focus_id; + + GtkWidget *panel; + GtkWidget *current_monitor_event_box; + GtkWidget *current_monitor_label; + GtkWidget *monitor_switch; + GtkListStore *resolution_store; + GtkWidget *resolution_combo; + GtkWidget *rotation_combo; + GtkWidget *clone_checkbox; + GtkWidget *clone_label; + GtkWidget *show_icon_checkbox; + + /* We store the event timestamp when the Apply button is clicked */ + guint32 apply_button_clicked_timestamp; + + GtkWidget *area; + gboolean ignore_gui_changes; + gboolean dragging_top_bar; + + /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */ + GDBusProxy *proxy; +}; + +typedef struct +{ + int grab_x; + int grab_y; + int output_x; + int output_y; +} GrabInfo; + +static void rebuild_gui (CcDisplayPanel *self); +static void on_clone_changed (GtkWidget *box, gpointer data); +static gboolean output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config); +static void select_current_output_from_dialog_position (CcDisplayPanel *self); +static void monitor_switch_active_cb (GObject *object, GParamSpec *pspec, gpointer data); +static void get_geometry (GnomeRROutputInfo *output, int *w, int *h); +static void apply_configuration_returned_cb (GObject *proxy, GAsyncResult *res, gpointer data); +static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height); +static gboolean output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height); +static char *make_resolution_string (int width, int height); +static GObject *cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties); +static void on_screen_changed (GnomeRRScreen *scr, gpointer data); +static void refresh_unity_launcher_placement (CcDisplayPanel *self); +static gboolean unity_launcher_on_all_monitors (GSettings *settings); + +static void +cc_display_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_dispose (GObject *object) +{ + G_OBJECT_CLASS (cc_display_panel_parent_class)->dispose (object); +} + +static void +cc_display_panel_finalize (GObject *object) +{ + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + + self = CC_DISPLAY_PANEL (object); + + g_signal_handlers_disconnect_by_func (self->priv->screen, on_screen_changed, self); + g_object_unref (self->priv->screen); + g_object_unref (self->priv->builder); + + if (self->priv->clock_settings != NULL) + g_object_unref (self->priv->clock_settings); + + if (self->priv->unity2d_settings_main != NULL) + g_object_unref (self->priv->unity2d_settings_main); + if (self->priv->unity2d_settings_launcher != NULL) + g_object_unref (self->priv->unity2d_settings_launcher); + if (self->priv->unity_settings != NULL) + g_object_unref (self->priv->unity_settings); + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (shell != NULL) + { + toplevel = cc_shell_get_toplevel (shell); + if (toplevel != NULL) + g_signal_handler_disconnect (G_OBJECT (toplevel), + self->priv->focus_id); + } + + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + + G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); +} + +static const char * +cc_display_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/prefs-display"; +} + +static void +cc_display_panel_class_init (CcDisplayPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcDisplayPanelPrivate)); + + panel_class->get_help_uri = cc_display_panel_get_help_uri; + + object_class->constructor = cc_display_panel_constructor; + object_class->get_property = cc_display_panel_get_property; + object_class->set_property = cc_display_panel_set_property; + object_class->dispose = cc_display_panel_dispose; + object_class->finalize = cc_display_panel_finalize; +} + +static void +error_message (CcDisplayPanel *self, const char *primary_text, const char *secondary_text) +{ + GtkWidget *toplevel; + GtkWidget *dialog; + + if (self && self->priv->panel) + toplevel = gtk_widget_get_toplevel (self->priv->panel); + else + toplevel = NULL; + + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + + if (secondary_text) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static gboolean +is_unity_session (void) +{ + return (g_strcmp0 (g_getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0); +} + +static gboolean +should_show_resolution (gint output_width, + gint output_height, + gint width, + gint height) +{ + if (width >= MIN (output_width, MINIMUM_WIDTH) && + height >= MIN (output_height, MINIMUM_HEIGHT)) + { + return TRUE; + } + return FALSE; +} + +static void +on_screen_changed (GnomeRRScreen *scr, + gpointer data) +{ + GnomeRRConfig *current; + CcDisplayPanel *self = data; + + current = gnome_rr_config_new_current (self->priv->screen, NULL); + gnome_rr_config_ensure_primary (current); + + if (self->priv->current_configuration) + g_object_unref (self->priv->current_configuration); + + self->priv->current_configuration = current; + self->priv->current_output = NULL; + + if (self->priv->labeler) { + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + } + + self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); + if (gtk_widget_has_focus (self->priv->panel)) + gnome_rr_labeler_show (self->priv->labeler); + + select_current_output_from_dialog_position (self); + + if (is_unity_session ()) + refresh_unity_launcher_placement (self); +} + +static void +on_viewport_changed (FooScrollArea *scroll_area, + GdkRectangle *old_viewport, + GdkRectangle *new_viewport) +{ + foo_scroll_area_set_size (scroll_area, + new_viewport->width, + new_viewport->height); + + foo_scroll_area_invalidate (scroll_area); +} + +static void +layout_set_font (PangoLayout *layout, const char *font) +{ + PangoFontDescription *desc = + pango_font_description_from_string (font); + + if (desc) + { + pango_layout_set_font_description (layout, desc); + + pango_font_description_free (desc); + } +} + +static void +clear_combo (GtkWidget *widget) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + GtkListStore *store = GTK_LIST_STORE (model); + + gtk_list_store_clear (store); +} + +typedef struct +{ + const char *text; + gboolean found; + GtkTreeIter iter; +} ForeachInfo; + +static gboolean +foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + ForeachInfo *info = data; + char *text = NULL; + + gtk_tree_model_get (model, iter, TEXT_COL, &text, -1); + + g_assert (text != NULL); + + if (strcmp (info->text, text) == 0) + { + info->found = TRUE; + info->iter = *iter; + return TRUE; + } + + return FALSE; +} + +static void +add_key (GtkTreeModel *model, + const char *text, + gboolean preferred, + int width, int height, int rate, + GnomeRRRotation rotation) +{ + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + { + GtkTreeIter iter; + g_debug ("adding %s with rate %d Hz", text, rate); + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, -1, + TEXT_COL, text, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + SORT_COL, width * 10000 + height, + ROTATION_COL, rotation, + -1); + return; + } + + /* Look, the preferred output, replace the old one */ + if (preferred) + { + g_debug ("replacing %s with rate %d Hz (preferred mode)", text, rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + + { + int old_rate; + + gtk_tree_model_get (model, &info.iter, + RATE_COL, &old_rate, + -1); + + /* Higher refresh rate */ + if (rate > old_rate) + { + g_debug ("replacing %s with rate %d Hz (old rate: %d)", text, rate, old_rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + } + + g_debug ("not adding %s with rate %d Hz (higher rate already there)", text, rate); +} + +static void +add_mode (CcDisplayPanel *self, + GnomeRRMode *mode, + gint output_width, + gint output_height, + guint preferred_id) +{ + int width, height, rate; + + width = gnome_rr_mode_get_width (mode); + height = gnome_rr_mode_get_height (mode); + rate = gnome_rr_mode_get_freq (mode); + + if (should_show_resolution (output_width, output_height, width, height)) + { + char *text; + gboolean preferred; + + preferred = (gnome_rr_mode_get_id (mode) == preferred_id); + text = make_resolution_string (width, height); + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->resolution_combo)), + text, preferred, width, height, rate, -1); + g_free (text); + } +} + + + +static gboolean +combo_select (GtkWidget *widget, const char *text) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + return FALSE; + + gtk_combo_box_set_active_iter (box, &info.iter); + return TRUE; +} + +static GnomeRRMode ** +get_current_modes (CcDisplayPanel *self) +{ + GnomeRROutput *output; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + return gnome_rr_screen_list_clone_modes (self->priv->screen); + } + else + { + if (!self->priv->current_output) + return NULL; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + + if (!output) + return NULL; + + return gnome_rr_output_list_modes (output); + } +} + +static void +rebuild_rotation_combo (CcDisplayPanel *self) +{ + typedef struct + { + GnomeRRRotation rotation; + const char * name; + } RotationInfo; + static const RotationInfo rotations[] = { + { GNOME_RR_ROTATION_0, NC_("display panel, rotation", "Normal") }, + { GNOME_RR_ROTATION_90, NC_("display panel, rotation", "Counterclockwise") }, + { GNOME_RR_ROTATION_270, NC_("display panel, rotation", "Clockwise") }, + { GNOME_RR_ROTATION_180, NC_("display panel, rotation", "180 Degrees") }, + }; + const char *selection; + GnomeRRRotation current; + int i; + + clear_combo (self->priv->rotation_combo); + + gtk_widget_set_sensitive (self->priv->rotation_combo, + self->priv->current_output && gnome_rr_output_info_is_active (self->priv->current_output)); + + if (!self->priv->current_output) + return; + + current = gnome_rr_output_info_get_rotation (self->priv->current_output); + + selection = NULL; + for (i = 0; i < G_N_ELEMENTS (rotations); ++i) + { + const RotationInfo *info = &(rotations[i]); + + gnome_rr_output_info_set_rotation (self->priv->current_output, info->rotation); + + /* NULL-GError --- FIXME: we should say why this rotation is not available! */ + if (gnome_rr_config_applicable (self->priv->current_configuration, self->priv->screen, NULL)) + { + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->rotation_combo)), g_dpgettext2 (NULL, "display panel, rotation", info->name), FALSE, 0, 0, 0, info->rotation); + + if (info->rotation == current) + selection = g_dpgettext2 (NULL, "display panel, rotation", info->name); + } + } + + gnome_rr_output_info_set_rotation (self->priv->current_output, current); + + if (!(selection && combo_select (self->priv->rotation_combo, selection))) + gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->rotation_combo), 0); +} + +static int +count_active_outputs (CcDisplayPanel *self) +{ + int i, count = 0; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_active (outputs[i])) + count++; + } + + return count; +} + +#if 0 +static int +count_all_outputs (GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) + ; + + return i; +} +#endif + +/* Computes whether "Mirror displays" (clone mode) is supported based on these criteria: + * + * 1. There is an available size for cloning. + * + * 2. There are 2 or more connected outputs that support that size. + */ +static gboolean +mirror_screens_is_supported (CcDisplayPanel *self) +{ + int clone_width, clone_height; + gboolean have_clone_size; + gboolean mirror_is_supported; + + mirror_is_supported = FALSE; + + have_clone_size = get_clone_size (self->priv->screen, &clone_width, &clone_height); + + if (have_clone_size) { + int i; + int num_outputs_with_clone_size; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + num_outputs_with_clone_size = 0; + + for (i = 0; outputs[i] != NULL; i++) + { + /* We count the connected outputs that support the clone size. It + * doesn't matter if those outputs aren't actually On currently; we + * will turn them on in on_clone_changed(). + */ + if (gnome_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (self, outputs[i], clone_width, clone_height)) + num_outputs_with_clone_size++; + } + + if (num_outputs_with_clone_size >= 2) + mirror_is_supported = TRUE; + } + + return mirror_is_supported; +} + +static void +rebuild_mirror_screens (CcDisplayPanel *self) +{ + gboolean mirror_is_active; + gboolean mirror_is_supported; + + g_signal_handlers_block_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); + + mirror_is_active = self->priv->current_configuration && gnome_rr_config_get_clone (self->priv->current_configuration); + + /* If mirror_is_active, then it *must* be possible to turn mirroring off */ + mirror_is_supported = mirror_is_active || mirror_screens_is_supported (self); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox), mirror_is_active); + gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); + gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); + + /* set inactive the launcher placement choice */ + gtk_widget_set_sensitive (WID ("launcher_placement_combo"), !mirror_is_active); + gtk_widget_set_sensitive (WID ("stickyedge_switch"), !mirror_is_active); + + g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); +} + +static char * +mirror_monitor_name (void) +{ + /* Keep this string in sync with gnome-desktop/libgnome-desktop/gnome-rr-labeler.c */ + + /* Translators: this is the feature where what you see on your laptop's + * screen is the same as your external projector. Here, "Mirrored" is being + * used as an adjective. For example, the Spanish translation could be + * "Pantallas en Espejo". + */ + return g_strdup (_("Mirrored Displays")); +} + +static void +rebuild_current_monitor_label (CcDisplayPanel *self) +{ + char *str, *tmp; + GdkRGBA color; + gboolean use_color; + + if (self->priv->current_output) + { + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + tmp = mirror_monitor_name (); + else + tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); + + str = g_strdup_printf ("%s", tmp); + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); + use_color = TRUE; + g_free (tmp); + } + else + { + str = g_strdup_printf ("%s", _("Monitor")); + use_color = FALSE; + } + + gtk_label_set_markup (GTK_LABEL (self->priv->current_monitor_label), str); + g_free (str); + + if (use_color) + { + GdkRGBA black = { 0, 0, 0, 1.0 }; + + gtk_widget_override_background_color (self->priv->current_monitor_event_box, + gtk_widget_get_state_flags (self->priv->current_monitor_event_box), + &color); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + &black); + } + else + { + /* Remove any modifications we did on the label's color */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + NULL); + } + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (self->priv->current_monitor_event_box), use_color); +} + +static void +rebuild_on_off_radios (CcDisplayPanel *self) +{ + gboolean sensitive; + gboolean on_active; + + g_signal_handlers_block_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); + + sensitive = FALSE; + on_active = FALSE; + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && self->priv->current_output) + { + if (count_active_outputs (self) > 1 || !gnome_rr_output_info_is_active (self->priv->current_output)) + sensitive = TRUE; + else + sensitive = FALSE; + + on_active = gnome_rr_output_info_is_active (self->priv->current_output); + } + + gtk_widget_set_sensitive (self->priv->monitor_switch, sensitive); + + gtk_switch_set_active (GTK_SWITCH (self->priv->monitor_switch), on_active); + + g_signal_handlers_unblock_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); +} + +static char * +make_resolution_string (int width, int height) +{ + int ratio; + const char *aspect = NULL; + + if (width && height) { + if (width > height) + ratio = width * 10 / height; + else + ratio = height * 10 / width; + + switch (ratio) { + case 13: + aspect = "4:3"; + break; + case 16: + aspect = "16:10"; + break; + case 17: + aspect = "16:9"; + break; + case 12: + aspect = "5:4"; + break; + /* This catches 1.5625 as well (1600x1024) when maybe it shouldn't. */ + case 15: + aspect = "3:2"; + break; + case 18: + aspect = "9:5"; + break; + case 10: + aspect = "1:1"; + break; + } + } + + if (aspect != NULL) + return g_strdup_printf (_("%d x %d (%s)"), width, height, aspect); + else + return g_strdup_printf (_("%d x %d"), width, height); +} + +static void +find_best_mode (GnomeRRMode **modes, int *out_width, int *out_height) +{ + int i; + + *out_width = 0; + *out_height = 0; + + for (i = 0; modes[i] != NULL; i++) + { + int w, h; + + w = gnome_rr_mode_get_width (modes[i]); + h = gnome_rr_mode_get_height (modes[i]); + + if (w * h > *out_width * *out_height) + { + *out_width = w; + *out_height = h; + } + } +} + +static void +rebuild_resolution_combo (CcDisplayPanel *self) +{ + int i; + GnomeRRMode **modes; + GnomeRRMode *mode; + char *current; + int output_width, output_height; + guint32 preferred_id; + GnomeRROutput *output; + + clear_combo (self->priv->resolution_combo); + + if (!(modes = get_current_modes (self)) + || !self->priv->current_output + || !gnome_rr_output_info_is_active (self->priv->current_output)) + { + gtk_widget_set_sensitive (self->priv->resolution_combo, FALSE); + return; + } + + g_assert (self->priv->current_output != NULL); + + gnome_rr_output_info_get_geometry (self->priv->current_output, NULL, NULL, &output_width, &output_height); + g_assert (output_width != 0 && output_height != 0); + + gtk_widget_set_sensitive (self->priv->resolution_combo, TRUE); + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + mode = gnome_rr_output_get_preferred_mode (output); + preferred_id = gnome_rr_mode_get_id (mode); + + for (i = 0; modes[i] != NULL; ++i) + add_mode (self, modes[i], output_width, output_height, preferred_id); + + /* And force the preferred mode in the drop-down (when not in clone mode) + * https://bugzilla.gnome.org/show_bug.cgi?id=680969 */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration)) + add_mode (self, mode, output_width, output_height, preferred_id); + + current = make_resolution_string (output_width, output_height); + + if (!combo_select (self->priv->resolution_combo, current)) + { + int best_w, best_h; + char *str; + + find_best_mode (modes, &best_w, &best_h); + str = make_resolution_string (best_w, best_h); + combo_select (self->priv->resolution_combo, str); + g_free (str); + } + + g_free (current); +} + +static void +rebuild_gui (CcDisplayPanel *self) +{ + /* We would break spectacularly if we recursed, so + * just assert if that happens + */ + g_assert (self->priv->ignore_gui_changes == FALSE); + + self->priv->ignore_gui_changes = TRUE; + + rebuild_mirror_screens (self); + rebuild_current_monitor_label (self); + rebuild_on_off_radios (self); + rebuild_resolution_combo (self); + rebuild_rotation_combo (self); + refresh_unity_launcher_placement (self); + + self->priv->ignore_gui_changes = FALSE; +} + +static gboolean +get_mode (GtkWidget *widget, int *width, int *height, int *rate, GnomeRRRotation *rot) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkComboBox *box = GTK_COMBO_BOX (widget); + int dummy; + + if (!gtk_combo_box_get_active_iter (box, &iter)) + return FALSE; + + if (!width) + width = &dummy; + + if (!height) + height = &dummy; + + if (!rate) + rate = &dummy; + + if (!rot) + rot = (GnomeRRRotation *)&dummy; + + model = gtk_combo_box_get_model (box); + gtk_tree_model_get (model, &iter, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + ROTATION_COL, rot, + -1); + + return TRUE; + +} + +static void +on_rotation_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + GnomeRRRotation rotation; + + if (!self->priv->current_output) + return; + + if (get_mode (self->priv->rotation_combo, NULL, NULL, NULL, &rotation)) + gnome_rr_output_info_set_rotation (self->priv->current_output, rotation); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +select_resolution_for_current_output (CcDisplayPanel *self) +{ + GnomeRRMode **modes; + int width, height; + int x,y; + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, NULL, NULL); + + width = gnome_rr_output_info_get_preferred_width (self->priv->current_output); + height = gnome_rr_output_info_get_preferred_height (self->priv->current_output); + + if (width != 0 && height != 0) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + return; + } + + modes = get_current_modes (self); + if (!modes) + return; + + find_best_mode (modes, &width, &height); + + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); +} + +static void +monitor_switch_active_cb (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + CcDisplayPanel *self = data; + gboolean value; + + if (!self->priv->current_output) + return; + + value = gtk_switch_get_active (GTK_SWITCH (object)); + + if (value) + { + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + select_resolution_for_current_output (self); + } + else + { + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + } + + rebuild_gui (self); + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +realign_outputs_after_resolution_change (CcDisplayPanel *self, GnomeRROutputInfo *output_that_changed, int old_width, int old_height) +{ + /* We find the outputs that were below or to the right of the output that + * changed, and realign them; we also do that for outputs that shared the + * right/bottom edges with the output that changed. The outputs that are + * above or to the left of that output don't need to change. + */ + + int i; + int old_right_edge, old_bottom_edge; + int dx, dy; + int x, y, width, height; + GnomeRROutputInfo **outputs; + + g_assert (self->priv->current_configuration != NULL); + + gnome_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height); + + if (width == old_width && height == old_height) + return; + + old_right_edge = x + old_width; + old_bottom_edge = y + old_height; + + dx = width - old_width; + dy = height - old_height; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; i++) + { + int output_x, output_y; + int output_width, output_height; + + if (outputs[i] == output_that_changed || !gnome_rr_output_info_is_connected (outputs[i])) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (output_x >= old_right_edge) + output_x += dx; + else if (output_x + output_width == old_right_edge) + output_x = x + width - output_width; + + if (output_y >= old_bottom_edge) + output_y += dy; + else if (output_y + output_height == old_bottom_edge) + output_y = y + height - output_height; + + gnome_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height); + } +} + +static void +on_resolution_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + int old_width, old_height; + int x,y; + int width; + int height; + + if (!self->priv->current_output) + return; + + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, &old_width, &old_height); + + if (get_mode (self->priv->resolution_combo, &width, &height, NULL, NULL)) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + + if (width == 0 || height == 0) + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + else + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + } + + realign_outputs_after_resolution_change (self, self->priv->current_output, old_width, old_height); + + rebuild_rotation_combo (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +lay_out_outputs_horizontally (CcDisplayPanel *self) +{ + int i; + int x; + GnomeRROutputInfo **outputs; + + /* Lay out all the monitors horizontally when "mirror screens" is turned + * off, to avoid having all of them overlapped initially. We put the + * outputs turned off on the right-hand side. + */ + + x = 0; + + /* First pass, all "on" outputs */ + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + + /* Second pass, all the black screens */ + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + +} + +/* FIXME: this function is copied from gnome-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c. + * Do we need to put this function in gnome-desktop for public use? + */ +static gboolean +get_clone_size (GnomeRRScreen *screen, int *width, int *height) +{ + GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); + int best_w, best_h; + int i; + + best_w = 0; + best_h = 0; + + for (i = 0; modes[i] != NULL; ++i) { + GnomeRRMode *mode = modes[i]; + int w, h; + + w = gnome_rr_mode_get_width (mode); + h = gnome_rr_mode_get_height (mode); + + if (w * h > best_w * best_h) { + best_w = w; + best_h = h; + } + } + + if (best_w > 0 && best_h > 0) { + if (width) + *width = best_w; + if (height) + *height = best_h; + + return TRUE; + } + + return FALSE; +} + +static gboolean +output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height) +{ + GnomeRROutput *output; + GnomeRRMode **modes; + int i; + + if (!gnome_rr_output_info_is_connected (info)) + return FALSE; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, gnome_rr_output_info_get_name (info)); + if (!output) + return FALSE; + + modes = gnome_rr_output_list_modes (output); + + for (i = 0; modes[i]; i++) { + if (gnome_rr_mode_get_width (modes[i]) == width + && gnome_rr_mode_get_height (modes[i]) == height) + return TRUE; + } + + return FALSE; +} + +static void +on_clone_changed (GtkWidget *box, gpointer data) +{ + CcDisplayPanel *self = data; + + gnome_rr_config_set_clone (self->priv->current_configuration, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox))); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + int i; + int width, height; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + self->priv->current_output = outputs[i]; + break; + } + } + + /* Turn on all the connected screens that support the best clone mode. + * The user may hit "Mirror displays", but he shouldn't have to turn on + * all the required outputs as well. + */ + + get_clone_size (self->priv->screen, &width, &height); + + for (i = 0; outputs[i]; i++) { + int x, y; + if (output_info_supports_mode (self, outputs[i], width, height)) { + gnome_rr_output_info_set_active (outputs[i], TRUE); + gnome_rr_output_info_get_geometry (outputs[i], &x, &y, NULL, NULL); + gnome_rr_output_info_set_geometry (outputs[i], x, y, width, height); + } + } + } + else + { + if (output_overlaps (self->priv->current_output, self->priv->current_configuration)) + lay_out_outputs_horizontally (self); + } + + rebuild_gui (self); +} + +static void +apply_rotation_to_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + GnomeRRRotation rotation; + + rotation = gnome_rr_output_info_get_rotation (output); + if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270)) + { + int tmp; + tmp = *h; + *h = *w; + *w = tmp; + } +} + +static void +get_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + if (gnome_rr_output_info_is_active (output)) + { + gnome_rr_output_info_get_geometry (output, NULL, NULL, w, h); + } + else + { + *h = gnome_rr_output_info_get_preferred_height (output); + *w = gnome_rr_output_info_get_preferred_width (output); + } + + apply_rotation_to_geometry (output, w, h); +} + +#define SPACE 15 +#define MARGIN 15 + +static GList * +list_connected_outputs (CcDisplayPanel *self, int *total_w, int *total_h) +{ + int i, dummy; + GList *result = NULL; + GnomeRROutputInfo **outputs; + + if (!total_w) + total_w = &dummy; + if (!total_h) + total_h = &dummy; + + *total_w = 0; + *total_h = 0; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + int w, h; + + result = g_list_prepend (result, outputs[i]); + + get_geometry (outputs[i], &w, &h); + + *total_w += w; + *total_h += h; + } + } + + return g_list_reverse (result); +} + +static int +get_n_connected (CcDisplayPanel *self) +{ + GList *connected_outputs = list_connected_outputs (self, NULL, NULL); + int n = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + return n; +} + +static double +compute_scale (CcDisplayPanel *self) +{ + int available_w, available_h; + int total_w, total_h; + int n_monitors; + GdkRectangle viewport; + GList *connected_outputs; + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + + connected_outputs = list_connected_outputs (self, &total_w, &total_h); + + n_monitors = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; + available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; + + return MIN ((double)available_w / total_w, (double)available_h / total_h); +} + +typedef struct Edge +{ + GnomeRROutputInfo *output; + int x1, y1; + int x2, y2; +} Edge; + +typedef struct Snap +{ + Edge *snapper; /* Edge that should be snapped */ + Edge *snappee; + int dy, dx; +} Snap; + +static void +add_edge (GnomeRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges) +{ + Edge e; + + e.x1 = x1; + e.x2 = x2; + e.y1 = y1; + e.y2 = y2; + e.output = output; + + g_array_append_val (edges, e); +} + +static void +list_edges_for_output (GnomeRROutputInfo *output, GArray *edges) +{ + int x, y, w, h; + + gnome_rr_output_info_get_geometry (output, &x, &y, &w, &h); + + apply_rotation_to_geometry (output, &w, &h); + + /* Top, Bottom, Left, Right */ + add_edge (output, x, y, x + w, y, edges); + add_edge (output, x, y + h, x + w, y + h, edges); + add_edge (output, x, y, x, y + h, edges); + add_edge (output, x + w, y, x + w, y + h, edges); +} + +static void +list_edges (GnomeRRConfig *config, GArray *edges) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + list_edges_for_output (outputs[i], edges); + } +} + +static gboolean +overlap (int s1, int e1, int s2, int e2) +{ + return (!(e1 < s2 || s1 >= e2)); +} + +static gboolean +horizontal_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) + return FALSE; + + return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); +} + +static gboolean +vertical_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) + return FALSE; + + return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); +} + +static void +add_snap (GArray *snaps, Snap snap) +{ + if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) + g_array_append_val (snaps, snap); +} + +static void +add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) +{ + Snap snap; + + snap.snapper = snapper; + snap.snappee = snappee; + + if (horizontal_overlap (snapper, snappee)) + { + snap.dx = 0; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + } + else if (vertical_overlap (snapper, snappee)) + { + snap.dy = 0; + snap.dx = snappee->x1 - snapper->x1; + + add_snap (snaps, snap); + } + + /* Corner snaps */ + /* 1->1 */ + snap.dx = snappee->x1 - snapper->x1; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + + /* 1->2 */ + snap.dx = snappee->x2 - snapper->x1; + snap.dy = snappee->y2 - snapper->y1; + + add_snap (snaps, snap); + + /* 2->2 */ + snap.dx = snappee->x2 - snapper->x2; + snap.dy = snappee->y2 - snapper->y2; + + add_snap (snaps, snap); + + /* 2->1 */ + snap.dx = snappee->x1 - snapper->x2; + snap.dy = snappee->y1 - snapper->y2; + + add_snap (snaps, snap); +} + +static void +list_snaps (GnomeRROutputInfo *output, GArray *edges, GArray *snaps) +{ + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + if (edge->output != output) + add_edge_snaps (output_edge, edge, snaps); + } + } + } +} + +#if 0 +static void +print_edge (Edge *edge) +{ + g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); +} +#endif + +static gboolean +corner_on_edge (int x, int y, Edge *e) +{ + if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) + return TRUE; + + if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) + return TRUE; + + return FALSE; +} + +static gboolean +edges_align (Edge *e1, Edge *e2) +{ + if (corner_on_edge (e1->x1, e1->y1, e2)) + return TRUE; + + if (corner_on_edge (e2->x1, e2->y1, e1)) + return TRUE; + + return FALSE; +} + +static gboolean +output_is_aligned (GnomeRROutputInfo *output, GArray *edges) +{ + gboolean result = FALSE; + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + /* We are aligned if an output edge matches + * an edge of another output + */ + if (edge->output != output_edge->output) + { + if (edges_align (output_edge, edge)) + { + result = TRUE; + goto done; + } + } + } + } + } + done: + + return result; +} + +static void +get_output_rect (GnomeRROutputInfo *output, GdkRectangle *rect) +{ + gnome_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); + + apply_rotation_to_geometry (output, &rect->width, &rect->height); +} + +static gboolean +output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config) +{ + int i; + GdkRectangle output_rect; + GnomeRROutputInfo **outputs; + + g_assert (output != NULL); + + get_output_rect (output, &output_rect); + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (outputs[i] != output && gnome_rr_output_info_is_connected (outputs[i])) + { + GdkRectangle other_rect; + + get_output_rect (outputs[i], &other_rect); + if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gnome_rr_config_is_aligned (GnomeRRConfig *config, GArray *edges) +{ + int i; + gboolean result = TRUE; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + if (!output_is_aligned (outputs[i], edges)) + return FALSE; + + if (output_overlaps (outputs[i], config)) + return FALSE; + } + } + + return result; +} + +static gboolean +is_corner_snap (const Snap *s) +{ + return s->dx != 0 && s->dy != 0; +} + +static int +compare_snaps (gconstpointer v1, gconstpointer v2) +{ + const Snap *s1 = v1; + const Snap *s2 = v2; + int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); + int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); + int d; + + d = sv1 - sv2; + + /* This snapping algorithm is good enough for rock'n'roll, but + * this is probably a better: + * + * First do a horizontal/vertical snap, then + * with the new coordinates from that snap, + * do a corner snap. + * + * Right now, it's confusing that corner snapping + * depends on the distance in an axis that you can't actually see. + * + */ + if (d == 0) + { + if (is_corner_snap (s1) && !is_corner_snap (s2)) + return -1; + else if (is_corner_snap (s2) && !is_corner_snap (s1)) + return 1; + else + return 0; + } + else + { + return d; + } +} + +/* Sets a mouse cursor for a widget's window. As a hack, you can pass + * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's + * window's cursor to its default). + */ +static void +set_cursor (GtkWidget *widget, GdkCursorType type) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (type == GDK_BLANK_CURSOR) + cursor = NULL; + else + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); + + window = gtk_widget_get_window (widget); + + if (window) + gdk_window_set_cursor (window, cursor); + + if (cursor) + g_object_unref (cursor); +} + +static void +set_top_bar_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Drag to change primary display."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +on_top_bar_event (FooScrollArea *area, + FooScrollAreaEvent *event, + CcDisplayPanel *self) +{ + /* Ignore drops */ + if (event->type == FOO_DROP) + return; + + /* If the mouse is inside the top bar, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_HAND1); + + if (event->type == FOO_BUTTON_PRESS) + { + rebuild_gui (self); + set_top_bar_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + self->priv->dragging_top_bar = TRUE; + foo_scroll_area_begin_grab (area, (FooScrollAreaEventFunc) on_top_bar_event, self); + } + + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + self->priv->dragging_top_bar = FALSE; + set_top_bar_tooltip (self, FALSE); + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +set_monitors_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Select a monitor to change its properties; drag it to rearrange its placement."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +set_primary_output (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + int i; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); + + gtk_widget_queue_draw (WID ("self->priv->area")); + /* refresh the combobox */ + refresh_unity_launcher_placement (self); +} + +static void +on_output_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + GnomeRROutputInfo *output = data; + CcDisplayPanel *self = g_object_get_data (G_OBJECT (area), "panel"); + + if (event->type == FOO_DRAG_HOVER) + { + if (gnome_rr_output_info_is_active (output) && self->priv->dragging_top_bar) + set_primary_output (self, output); + return; + } + if (event->type == FOO_DROP) + { + /* Activate new primary? */ + return; + } + + /* If the mouse is inside the outputs, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_FLEUR); + + if (event->type == FOO_BUTTON_PRESS) + { + GrabInfo *info; + + self->priv->current_output = output; + + rebuild_gui (self); + set_monitors_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + int output_x, output_y; + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + + foo_scroll_area_begin_grab (area, on_output_event, data); + + info = g_new0 (GrabInfo, 1); + info->grab_x = event->x; + info->grab_y = event->y; + info->output_x = output_x; + info->output_y = output_y; + + g_object_set_data (G_OBJECT (output), "grab-info", info); + } + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); + double scale = compute_scale (self); + int old_x, old_y; + int width, height; + int new_x, new_y; + int i; + GArray *edges, *snaps, *new_edges; + + gnome_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height); + new_x = info->output_x + (event->x - info->grab_x) / scale; + new_y = info->output_y + (event->y - info->grab_y) / scale; + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); + new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + list_edges (self->priv->current_configuration, edges); + list_snaps (output, edges, snaps); + + g_array_sort (snaps, compare_snaps); + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + for (i = 0; i < snaps->len; ++i) + { + Snap *snap = &(g_array_index (snaps, Snap, i)); + GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + gnome_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height); + + g_array_set_size (new_edges, 0); + list_edges (self->priv->current_configuration, new_edges); + + if (gnome_rr_config_is_aligned (self->priv->current_configuration, new_edges)) + { + g_array_free (new_edges, TRUE); + break; + } + else + { + gnome_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height); + } + } + + g_array_free (new_edges, TRUE); + g_array_free (snaps, TRUE); + g_array_free (edges, TRUE); + + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + set_monitors_tooltip (self, FALSE); + + g_free (g_object_get_data (G_OBJECT (output), "grab-info")); + g_object_set_data (G_OBJECT (output), "grab-info", NULL); + +#if 0 + g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); +#endif + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +on_canvas_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + /* If the mouse exits the outputs, reset the cursor to the default. See + * on_output_event() for where we set the cursor to the movement cursor if + * it is over one of the outputs. + */ + set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); +} + +static PangoLayout * +get_display_name (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + PangoLayout *layout; + char *text; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + text = mirror_monitor_name (); + else + text = g_strdup (gnome_rr_output_info_get_display_name (output)); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + return layout; +} + +static void +paint_background (FooScrollArea *area, + cairo_t *cr) +{ + GdkRectangle viewport; + GtkWidget *widget; + GtkStyleContext *context; + GdkRGBA fg, bg; + + widget = GTK_WIDGET (area); + + foo_scroll_area_get_viewport (area, &viewport); + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg); + + cairo_set_source_rgba (cr, + (fg.red + bg.red) / 2, + (fg.green + bg.green) / 2, + (fg.blue + bg.blue) / 2, + (fg.alpha + bg.alpha) / 2); + + cairo_rectangle (cr, + viewport.x, viewport.y, + viewport.width, viewport.height); + + cairo_fill_preserve (cr); + + foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); + + cairo_set_source_rgba (cr, + 0.7 * bg.red, + 0.7 * bg.green, + 0.7 * bg.blue, + 0.7 * bg.alpha); + + cairo_stroke (cr); +} + +static void +color_shade (double *r, + double *g, + double *b, + double k) +{ + double h, s, v; + + gtk_rgb_to_hsv (*r, *g, *b, &h, &s, &v); + + s *= k; + if (s > 1.0) + s = 1.0; + else if (s < 0.0) + s = 0.0; + + v *= k; + if (v > 1.0) + v = 1.0; + else if (v < 0.0) + v = 0.0; + + gtk_hsv_to_rgb (h, s, v, r, g, b); +} + +static void +paint_output (CcDisplayPanel *self, cairo_t *cr, int i) +{ + int w, h; + double scale = compute_scale (self); + double x, y; + int output_x, output_y; + GnomeRRRotation rotation; + int total_w, total_h; + GList *connected_outputs = list_connected_outputs (self, &total_w, &total_h); + GnomeRROutputInfo *output = g_list_nth (connected_outputs, i)->data; + PangoLayout *layout = get_display_name (self, output); + PangoRectangle ink_extent, log_extent; + GdkRectangle viewport; + GdkRGBA output_color; + double r, g, b; + double available_w; + double factor; + + cairo_save (cr); + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + get_geometry (output, &w, &h); + +#if 0 + g_debug ("%s (%p) geometry %d %d %d primary=%d", output->name, output->name, + w, h, output->rate, output->primary); +#endif + + viewport.height -= 2 * MARGIN; + viewport.width -= 2 * MARGIN; + + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; + y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; + +#if 0 + g_debug ("scaled: %f %f", x, y); + + g_debug ("scale: %f", scale); + + g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5); +#endif + + cairo_translate (cr, + x + (w * scale + 0.5) / 2, + y + (h * scale + 0.5) / 2); + + /* rotation is already applied in get_geometry */ + + rotation = gnome_rr_output_info_get_rotation (output); + if (rotation & GNOME_RR_REFLECT_X) + cairo_scale (cr, -1, 1); + + if (rotation & GNOME_RR_REFLECT_Y) + cairo_scale (cr, 1, -1); + + cairo_translate (cr, + - x - (w * scale + 0.5) / 2, + - y - (h * scale + 0.5) / 2); + + if (output == self->priv->current_output) + { + GtkStyleContext *context; + GdkRGBA color; + + context = gtk_widget_get_style_context (self->priv->area); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); + + cairo_rectangle (cr, x - 2, y - 2, w * scale + 0.5 + 4, h * scale + 0.5 + 4); + + cairo_set_line_width (cr, 4); + cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5); + cairo_stroke (cr); + } + + cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); + cairo_clip_preserve (cr); + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); + r = output_color.red; + g = output_color.green; + b = output_color.blue; + + if (!gnome_rr_output_info_is_active (output)) + { + /* If the output is turned off, just darken the selected color */ + color_shade (&r, &g, &b, 0.4); + } + + cairo_set_source_rgba (cr, r, g, b, 1.0); + + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, on_output_event, output); + cairo_fill (cr); + + cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + + cairo_stroke (cr); + cairo_set_line_width (cr, 2); + + cairo_save (cr); + + layout_set_font (layout, "Sans 10"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */ + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + ((h * scale + 0.5) - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + if (gnome_rr_output_info_is_active (output)) + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + else + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + cairo_restore (cr); + + /* Only display a launcher on all or primary monitor */ + if (is_unity_session ()) + { + if (gnome_rr_output_info_is_active (output) && (unity_launcher_on_all_monitors (self->priv->unity_settings) || gnome_rr_output_info_get_primary (output))) + { + cairo_rectangle (cr, x, y, 10, h * scale + 0.5); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + cairo_rectangle (cr, x + 1, y + 6, 8, 8); + cairo_rectangle (cr, x + 1, y + 16, 8, 8); + cairo_rectangle (cr, x + 1, y + 26, 8, 8); + cairo_rectangle (cr, x + 1, y + 36, 8, 8); + cairo_rectangle (cr, x + 1, y + h * scale + 0.5 - 10, 8, 8); + cairo_fill (cr); + } + } + + if (gnome_rr_output_info_get_primary (output) && !is_unity_session ()) + { + const char *clock_format; + char *text; + gboolean use_24; + GDateTime *dt; + GDesktopClockFormat value; + + /* top bar */ + cairo_rectangle (cr, x, y, w * scale + 0.5, TOP_BAR_HEIGHT); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + + cairo_fill (cr); + + /* clock */ + value = g_settings_get_enum (self->priv->clock_settings, CLOCK_FORMAT_KEY); + use_24 = value == G_DESKTOP_CLOCK_FORMAT_24H; + if (use_24) + clock_format = _("%a %R"); + else + clock_format = _("%a %l:%M %p"); + + dt = g_date_time_new_now_local (); + text = g_date_time_format (dt, clock_format); + g_date_time_unref (dt); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + layout_set_font (layout, "Sans 4"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + (TOP_BAR_HEIGHT - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + } + + cairo_restore (cr); +} + +static void +on_area_paint (FooScrollArea *area, + cairo_t *cr, + gpointer data) +{ + CcDisplayPanel *self = data; + GList *connected_outputs = NULL; + GList *list; + + paint_background (area, cr); + + if (!self->priv->current_configuration) + return; + + connected_outputs = list_connected_outputs (self, NULL, NULL); + + for (list = connected_outputs; list != NULL; list = list->next) + { + paint_output (self, cr, g_list_position (connected_outputs, list)); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + break; + } +} + +static void +make_text_combo (GtkWidget *widget, int sort_column) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkListStore *store = gtk_list_store_new ( + NUM_COLS, + G_TYPE_STRING, /* Text */ + G_TYPE_INT, /* Width */ + G_TYPE_INT, /* Height */ + G_TYPE_INT, /* Frequency */ + G_TYPE_INT, /* Width * Height */ + G_TYPE_INT); /* Rotation */ + + GtkCellRenderer *cell; + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget)); + + gtk_combo_box_set_model (box, GTK_TREE_MODEL (store)); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell, + "text", 0, + NULL); + + if (sort_column != -1) + { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + sort_column, + GTK_SORT_DESCENDING); + } +} + +static void +compute_virtual_size_for_configuration (GnomeRRConfig *config, int *ret_width, int *ret_height) +{ + int i; + int width, height; + int output_x, output_y, output_width, output_height; + GnomeRROutputInfo **outputs; + + width = height = 0; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) + { + if (gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + width = MAX (width, output_x + output_width); + height = MAX (height, output_y + output_height); + } + } + + *ret_width = width; + *ret_height = height; +} + +static void +check_required_virtual_size (CcDisplayPanel *self) +{ + int req_width, req_height; + int min_width, max_width; + int min_height, max_height; + + compute_virtual_size_for_configuration (self->priv->current_configuration, &req_width, &req_height); + + gnome_rr_screen_get_ranges (self->priv->screen, &min_width, &max_width, &min_height, &max_height); + +#if 0 + g_debug ("X Server supports:"); + g_debug ("min_width = %d, max_width = %d", min_width, max_width); + g_debug ("min_height = %d, max_height = %d", min_height, max_height); + + g_debug ("Requesting size of %dx%d", req_width, req_height); +#endif + + if (!(min_width <= req_width && req_width <= max_width + && min_height <= req_height && req_height <= max_height)) + { + /* FIXME: present a useful dialog, maybe even before the user tries to Apply */ +#if 0 + g_debug ("Your X server needs a larger Virtual size!"); +#endif + } +} + +static void +begin_version2_apply_configuration (CcDisplayPanel *self, GdkWindow *parent_window, guint32 timestamp) +{ + XID parent_window_xid; + GError *error = NULL; + + parent_window_xid = GDK_WINDOW_XID (parent_window); + + self->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/XRANDR", + "org.gnome.SettingsDaemon.XRANDR_2", + NULL, + &error); + if (self->priv->proxy == NULL) { + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_error_free (error); + return; + } + + g_dbus_proxy_call (self->priv->proxy, + "ApplyConfiguration", + g_variant_new ("(xx)", (gint64) parent_window_xid, (gint64) timestamp), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + apply_configuration_returned_cb, + self); +} + +static void +ensure_current_configuration_is_saved (void) +{ + GnomeRRScreen *rr_screen; + GnomeRRConfig *rr_config; + + /* Normally, gnome_rr_config_save() creates a backup file based on the + * old monitors.xml. However, if *that* file didn't exist, there is + * nothing from which to create a backup. So, here we'll save the + * current/unchanged configuration and then let our caller call + * gnome_rr_config_save() again with the new/changed configuration, so + * that there *will* be a backup file in the end. + */ + + rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL); /* NULL-GError */ + if (!rr_screen) + return; + + rr_config = gnome_rr_config_new_current (rr_screen, NULL); + gnome_rr_config_ensure_primary (rr_config); + gnome_rr_config_save (rr_config, NULL); /* NULL-GError */ + + g_object_unref (rr_config); + g_object_unref (rr_screen); +} + +static void +apply_configuration_returned_cb (GObject *proxy, + GAsyncResult *res, + gpointer data) +{ + CcDisplayPanel *self = data; + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if (error) + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_clear_error (&error); + if (result) + g_variant_unref (result); + + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + + gtk_widget_set_sensitive (self->priv->panel, TRUE); +} + +static gboolean +sanitize_and_save_configuration (CcDisplayPanel *self) +{ + GError *error; + + gnome_rr_config_sanitize (self->priv->current_configuration); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + + check_required_virtual_size (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); + + ensure_current_configuration_is_saved (); + + error = NULL; + if (!gnome_rr_config_save (self->priv->current_configuration, &error)) + { + error_message (self, _("Could not save the monitor configuration"), error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +static void +apply (CcDisplayPanel *self) +{ + GdkWindow *window; + + self->priv->apply_button_clicked_timestamp = gtk_get_current_event_time (); + + if (!sanitize_and_save_configuration (self)) + return; + + g_assert (self->priv->proxy == NULL); + + gtk_widget_set_sensitive (self->priv->panel, FALSE); + + window = gtk_widget_get_window (gtk_widget_get_toplevel (self->priv->panel)); + + begin_version2_apply_configuration (self, window, + self->priv->apply_button_clicked_timestamp); +} + +#if 0 +/* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */ +static gboolean +driver_is_randr_10 (GnomeRRConfig *config) +{ + /* In the Xorg code, see xserver/randr/rrinfo.c:RRScanOldConfig(). It gets + * called when the graphics driver doesn't support RANDR 1.2 yet, just 1.0. + * In that case, the X server's base code (which supports RANDR 1.2) will + * simulate having a single output called "default". For drivers that *do* + * support RANDR 1.2, the separate outputs will be named differently, we + * hope. + * + * This heuristic is courtesy of Dirk Mueller + * + * FIXME: however, we don't even check for XRRQueryVersion() returning 1.2, neither + * here nor in gnome-desktop/libgnomedesktop*.c. Do we need to check for that, + * or is gnome_rr_screen_new()'s return value sufficient? + */ + + return (count_all_outputs (config) == 1 && strcmp (gnome_rr_output_info_get_name (gnome_rr_config_get_outputs (config)[0]), "default") == 0); +} +#endif + +static void +on_detect_displays (GtkWidget *widget, gpointer data) +{ + CcDisplayPanel *self = data; + GError *error; + + error = NULL; + if (!gnome_rr_screen_refresh (self->priv->screen, &error)) { + if (error) { + error_message (self, _("Could not detect displays"), error->message); + g_error_free (error); + } + } +} + +static GnomeRROutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) +{ + int i; + int nearest_index; + int nearest_dist; + GnomeRROutputInfo **outputs; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + int dist_x, dist_y; + int output_x, output_y, output_width, output_height; + + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (x < output_x) + dist_x = output_x - x; + else if (x >= output_x + output_width) + dist_x = x - (output_x + output_width) + 1; + else + dist_x = 0; + + if (y < output_y) + dist_y = output_y - y; + else if (y >= output_y + output_height) + dist_y = y - (output_y + output_height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return outputs[nearest_index]; + else + return NULL; +} + +/* Gets the output that contains the largest intersection with the window. + * Logic stolen from gdk_screen_get_monitor_at_window(). + */ +static GnomeRROutputInfo * +get_output_for_window (GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + GnomeRROutputInfo **outputs; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + GdkRectangle output_rect, intersection; + + gnome_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); + + if (gnome_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +static void +dialog_toplevel_focus_changed (GtkWindow *window, + GParamSpec *pspec, + CcDisplayPanel *self) +{ + if (self->priv->labeler == NULL) + return; + if (gtk_window_has_toplevel_focus (window)) + gnome_rr_labeler_show (self->priv->labeler); + else + gnome_rr_labeler_hide (self->priv->labeler); +} + +static void +on_toplevel_realized (GtkWidget *widget, + CcDisplayPanel *self) +{ + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (widget)); + rebuild_gui (self); +} + +/* We select the current output, i.e. select the one being edited, based on + * which output is showing the configuration dialog. + */ +static void +select_current_output_from_dialog_position (CcDisplayPanel *self) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (self->priv->panel); + + if (gtk_widget_get_realized (toplevel)) { + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (toplevel)); + rebuild_gui (self); + } else { + g_signal_connect (toplevel, "realize", G_CALLBACK (on_toplevel_realized), self); + self->priv->current_output = NULL; + } +} + +/* This is a GtkWidget::map-event handler. We wait for the display-properties + * dialog to be mapped, and then we select the output which corresponds to the + * monitor on which the dialog is being shown. + */ +static gboolean +dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + CcDisplayPanel *self = data; + + select_current_output_from_dialog_position (self); + return FALSE; +} + +static void +stickyedge_widget_refresh (GtkSwitch *switcher, GSettings *settings) +{ + gboolean stickyedge_enabled = g_settings_get_boolean (settings, UNITY_STICKY_EDGE_KEY); + + gtk_switch_set_active (switcher, stickyedge_enabled); +} + +static void +ext_stickyedge_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + stickyedge_widget_refresh (GTK_SWITCH (user_data), settings); +} + +static void +on_stickyedge_changed (GtkSwitch *switcher, GParamSpec *pspec, gpointer user_data) +{ + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gboolean enabled = gtk_switch_get_active (GTK_SWITCH (switcher)); + + /* 3d */ + g_settings_set_boolean (self->priv->unity_settings, UNITY_STICKY_EDGE_KEY, enabled); + /* 2d */ + if (self->priv->unity2d_settings_main) + g_settings_set_boolean (self->priv->unity2d_settings_main, "sticky-edges", enabled); +} + +static gboolean +unity_launcher_on_all_monitors (GSettings *settings) +{ + gint value = g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY); + return (value == 0); +} + +static GdkPixbuf* +get_monitor_pixbuf (CcDisplayPanel *self, GnomeRROutputInfo *output) +{ + GdkRGBA color; + cairo_surface_t *cairo_surface; + cairo_t *cr; + int monitor_width = 30; + int monitor_height = 15; + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); + + cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); + cr = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, color.red, color.green, color.blue); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0, 0, 0, 1.0); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_stroke (cr); + + return gdk_pixbuf_get_from_surface (cairo_get_target (cr), 0, 0, monitor_width, monitor_height); +} + +static void +refresh_unity_launcher_placement (CcDisplayPanel *self) +{ + GtkWidget *launcher_placement_combo = WID ("launcher_placement_combo"); + GtkListStore *liststore; + GtkTreeIter iter; + GList *connected_outputs = NULL; + GList *list; + gboolean launcher_on_all_monitors = unity_launcher_on_all_monitors (self->priv->unity_settings); + gint index_of_primary_screen = 0; + gint i; + + liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "available_launcher_placement_store"); + gtk_list_store_clear (liststore); + + connected_outputs = list_connected_outputs (self, NULL, NULL); + for (list = connected_outputs, i = 0; list != NULL; list = list->next) + { + char *monitor_name; + GdkPixbuf *monitor_pixbuf; + GnomeRROutputInfo *output = list->data; + + if (!gnome_rr_output_info_is_active (output)) + continue; + + gtk_list_store_append (liststore, &iter); + monitor_name = g_strdup (gnome_rr_output_info_get_display_name (output)); + monitor_pixbuf = get_monitor_pixbuf (self, output); + + gtk_list_store_set (liststore, &iter, 0, monitor_pixbuf, 1, monitor_name, -1); + + /* select it if primary and only one launcher */ + if (gnome_rr_output_info_get_primary (output) && (!launcher_on_all_monitors)) + index_of_primary_screen = i; + i++; + + g_object_unref (monitor_pixbuf); + g_free (monitor_name); + } + + // FIXME: check autosort? + gtk_list_store_append (liststore, &iter); + gtk_list_store_set (liststore, &iter, 0, NULL, 1, _("All displays"), -1); + + if (launcher_on_all_monitors) + index_of_primary_screen = i; + + gtk_combo_box_set_active (GTK_COMBO_BOX (launcher_placement_combo), index_of_primary_screen); +} + +static gboolean +switcher_set_to_launcher_on_all_monitors (CcDisplayPanel *self) +{ + GtkComboBox *combo = GTK_COMBO_BOX (WID ("launcher_placement_combo")); + gint active = gtk_combo_box_get_active (combo); + gint number_items = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), + NULL); + return (active == number_items - 1); +} + +static void +ext_launcher_placement_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + // add some crazyness as 2d/3d are not using the same keys + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gint launcher_unity_value = 0; + + // two options support: all monitors (0)i or just primary desktop (hence set to 1, not any other number) + if (! switcher_set_to_launcher_on_all_monitors (self)) + launcher_unity_value = 1; + + if (g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY) != launcher_unity_value) + refresh_unity_launcher_placement (self); +} + +static void +on_launcher_placement_combo_changed (GtkComboBox *combo, CcDisplayPanel *self) +{ + gint active = gtk_combo_box_get_active (combo); + gint i; + gint index_on_combo = 0; + + if (active < 0) + return; + gint value = 0; + gboolean on_all_monitors = switcher_set_to_launcher_on_all_monitors (self); + + if (!on_all_monitors) { + value = 1; + // set the primary output if needed + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + GnomeRROutputInfo *output = outputs[i]; + if (!gnome_rr_output_info_is_active (output)) + continue; + + if ((active == index_on_combo) && !gnome_rr_output_info_get_primary (output)) + { + set_primary_output (self, output); + break; + } + index_on_combo++; + } + } + + /* 3d */ + if (self->priv->unity_settings) + g_settings_set_int (self->priv->unity_settings, UNITY_LAUNCHER_ALL_MONITORS_KEY, value); + /* 2d */ + if (self->priv->unity2d_settings_launcher) + g_settings_set_boolean (self->priv->unity2d_settings_launcher, "only-one-launcher", !on_all_monitors); +} + +static void +setup_unity_settings (CcDisplayPanel *self) +{ + const gchar * const *schemas; + + /* Only use the unity-2d schema if it's installed */ + schemas = g_settings_list_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY2D_GSETTINGS_LAUNCHER) == 0) + { + self->priv->unity2d_settings_main = g_settings_new (UNITY2D_GSETTINGS_MAIN); + self->priv->unity2d_settings_launcher = g_settings_new (UNITY2D_GSETTINGS_LAUNCHER); + break; + } + schemas++; + } + schemas = g_settings_list_relocatable_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY_GSETTINGS_SCHEMA) == 0) + { + self->priv->unity_settings = g_settings_new_with_path (UNITY_GSETTINGS_SCHEMA, UNITY_GSETTINGS_PATH); + break; + } + schemas++; + } + + if (!self->priv->unity_settings) + return; + + GtkWidget *sticky_edge_switch = WID ("stickyedge_switch"); + g_signal_connect (sticky_edge_switch, "notify::active", + G_CALLBACK (on_stickyedge_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_STICKY_EDGE_KEY, + G_CALLBACK (ext_stickyedge_changed_callback), sticky_edge_switch); + stickyedge_widget_refresh (GTK_SWITCH (sticky_edge_switch), self->priv->unity_settings); + + g_signal_connect (G_OBJECT (WID ("launcher_placement_combo")), "changed", + G_CALLBACK (on_launcher_placement_combo_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_LAUNCHER_ALL_MONITORS_KEY, + G_CALLBACK (ext_launcher_placement_changed_callback), self); +} + +static void +cc_display_panel_init (CcDisplayPanel *self) +{ +} + +static GObject * +cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) +{ + GtkBuilder *builder; + GtkWidget *align; + GError *error; + GObject *obj; + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + gchar *objects[] = {"display-panel", "available_launcher_placement_store", NULL}; + + obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); + self = CC_DISPLAY_PANEL (obj); + self->priv = DISPLAY_PANEL_PRIVATE (self); + + error = NULL; + self->priv->builder = builder = gtk_builder_new (); + + if (!gtk_builder_add_objects_from_file (builder, UIDIR "/display-capplet.ui", objects, &error)) + { + g_warning ("Could not parse UI definition: %s", error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); + g_signal_connect (self->priv->screen, "changed", G_CALLBACK (on_screen_changed), self); + if (!self->priv->screen) + { + error_message (NULL, _("Could not get screen information"), error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->clock_settings = g_settings_new (CLOCK_SCHEMA); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + self->priv->focus_id = g_signal_connect (toplevel, "notify::has-toplevel-focus", + G_CALLBACK (dialog_toplevel_focus_changed), self); + + self->priv->panel = WID ("display-panel"); + g_signal_connect_after (self->priv->panel, "show", + G_CALLBACK (dialog_map_event_cb), self); + + self->priv->current_monitor_event_box = WID ("current_monitor_event_box"); + self->priv->current_monitor_label = WID ("current_monitor_label"); + + self->priv->monitor_switch = WID ("monitor_switch"); + g_signal_connect (self->priv->monitor_switch, "notify::active", + G_CALLBACK (monitor_switch_active_cb), self); + + self->priv->resolution_combo = WID ("resolution_combo"); + g_signal_connect (self->priv->resolution_combo, "changed", + G_CALLBACK (on_resolution_changed), self); + + self->priv->rotation_combo = WID ("rotation_combo"); + g_signal_connect (self->priv->rotation_combo, "changed", + G_CALLBACK (on_rotation_changed), self); + + self->priv->clone_checkbox = WID ("clone_checkbox"); + g_signal_connect (self->priv->clone_checkbox, "toggled", + G_CALLBACK (on_clone_changed), self); + + self->priv->clone_label = WID ("clone_resolution_warning_label"); + + g_signal_connect (WID ("detect_displays_button"), + "clicked", G_CALLBACK (on_detect_displays), self); + + make_text_combo (self->priv->resolution_combo, 4); + make_text_combo (self->priv->rotation_combo, -1); + + /* Scroll Area */ + self->priv->area = (GtkWidget *)foo_scroll_area_new (); + + g_object_set_data (G_OBJECT (self->priv->area), "panel", self); + + set_monitors_tooltip (self, FALSE); + + /* FIXME: this should be computed dynamically */ + foo_scroll_area_set_min_size (FOO_SCROLL_AREA (self->priv->area), 0, 200); + gtk_widget_show (self->priv->area); + g_signal_connect (self->priv->area, "paint", + G_CALLBACK (on_area_paint), self); + g_signal_connect (self->priv->area, "viewport_changed", + G_CALLBACK (on_viewport_changed), self); + + align = WID ("align"); + + gtk_container_add (GTK_CONTAINER (align), self->priv->area); + + on_screen_changed (self->priv->screen, self); + + g_signal_connect_swapped (WID ("apply_button"), + "clicked", G_CALLBACK (apply), self); + + /* Unity settings */ + if (is_unity_session ()) + setup_unity_settings (self); + else + { + gtk_widget_hide (WID ("unity_launcher_placement_sep")); + gtk_widget_hide (WID ("launcher_placement_label")); + gtk_widget_hide (WID ("sticky_edge_label")); + gtk_widget_hide (WID ("launcher_placement_combo")); + gtk_widget_hide (WID ("stickyedge_switch")); + } + + gtk_widget_show (self->priv->panel); + gtk_container_add (GTK_CONTAINER (self), self->priv->panel); + + return obj; +} + +void +cc_display_panel_register (GIOModule *module) +{ + cc_display_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_DISPLAY_PANEL, + "display", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/mouse/cc-mouse-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/mouse/cc-mouse-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/mouse/cc-mouse-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/mouse/cc-mouse-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2012 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Thomas Wood + * Rodrigo Moya + * Ondrej Holy + * + */ + +#include "cc-mouse-panel.h" +#include "gnome-mouse-properties.h" +#include "gnome-mouse-test.h" +#include + +#include + +CC_PANEL_REGISTER (CcMousePanel, cc_mouse_panel) + +#define MOUSE_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_MOUSE_PANEL, CcMousePanelPrivate)) + +#define WID(x) (GtkWidget*) gtk_builder_get_object (dialog, x) + +struct _CcMousePanelPrivate +{ + GtkBuilder *builder; + GtkWidget *widget; + GtkWidget *prefs_widget; + GtkWidget *test_widget; + GtkWidget *shell_header; +}; + +enum { + CC_MOUSE_PAGE_PREFS, + CC_MOUSE_PAGE_TEST +}; + +static void +cc_mouse_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_mouse_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_mouse_panel_dispose (GObject *object) +{ + CcMousePanelPrivate *priv = CC_MOUSE_PANEL (object)->priv; + + g_clear_object (&priv->shell_header); + + if (priv->prefs_widget) + { + gnome_mouse_properties_dispose (priv->prefs_widget); + priv->prefs_widget = NULL; + } + + if (priv->test_widget) + { + gnome_mouse_test_dispose (priv->test_widget); + priv->test_widget = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + G_OBJECT_CLASS (cc_mouse_panel_parent_class)->dispose (object); +} + +static const char * +cc_mouse_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/mouse"; +} + +static void +cc_mouse_panel_class_init (CcMousePanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcMousePanelPrivate)); + + panel_class->get_help_uri = cc_mouse_panel_get_help_uri; + + object_class->get_property = cc_mouse_panel_get_property; + object_class->set_property = cc_mouse_panel_set_property; + object_class->dispose = cc_mouse_panel_dispose; +} + +/* Toggle between mouse panel properties and testing area. */ +static void +shell_test_button_toggle_event (GtkToggleButton *button, CcMousePanel *panel) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (panel->priv->widget); + gint page_num; + + if (gtk_toggle_button_get_active (button)) { + GtkBuilder *dialog = panel->priv->builder; + GtkAdjustment *adjustment; + + page_num = CC_MOUSE_PAGE_TEST; + + adjustment = GTK_ADJUSTMENT (WID ("scrolled_window_adjustment")); + gtk_adjustment_set_value (adjustment, + gtk_adjustment_get_upper (adjustment)); + } else { + page_num = CC_MOUSE_PAGE_PREFS; + } + + gtk_notebook_set_current_page (notebook, page_num); +} + +/* Add test area toggle to shell header. */ +static gboolean +add_shell_test_button_cb (gpointer user_data) +{ + CcMousePanel *panel = CC_MOUSE_PANEL (user_data); + GtkWidget *box, *button; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); + + button = gtk_toggle_button_new_with_mnemonic (_("_Test Your Settings")); + gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); + gtk_widget_set_visible (button, TRUE); + + cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (panel)), box); + gtk_widget_set_visible (box, TRUE); + + panel->priv->shell_header = g_object_ref (box); + + g_signal_connect (GTK_BUTTON (button), "toggled", + G_CALLBACK (shell_test_button_toggle_event), + panel); + + return FALSE; +} + +static void +cc_mouse_panel_init (CcMousePanel *self) +{ + CcMousePanelPrivate *priv; + GtkBuilder *dialog; + GError *error = NULL; + + priv = self->priv = MOUSE_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_from_file (priv->builder, + GNOMECC_UI_DIR "/gnome-mouse-properties.ui", + &error); + if (error != NULL) + { + g_warning ("Error loading UI file: %s", error->message); + return; + } + + gtk_builder_add_from_file (priv->builder, + GNOMECC_UI_DIR "/gnome-mouse-test.ui", + &error); + if (error != NULL) + { + g_warning ("Error loading UI file: %s", error->message); + return; + } + + dialog = priv->builder; + + priv->prefs_widget = gnome_mouse_properties_init (priv->builder); + priv->test_widget = gnome_mouse_test_init (priv->builder); + + priv->widget = gtk_notebook_new (); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->widget), FALSE); + gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->widget), FALSE); + + gtk_widget_reparent (WID ("prefs_widget"), priv->widget); + gtk_widget_reparent (WID ("test_widget"), priv->widget); + + gtk_container_add (GTK_CONTAINER (self), priv->widget); + gtk_widget_show (priv->widget); + + g_idle_add (add_shell_test_button_cb, self); +} + +void +cc_mouse_panel_register (GIOModule *module) +{ + cc_mouse_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_MOUSE_PANEL, + "mouse", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/network/cc-network-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/network/cc-network-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/network/cc-network-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/network/cc-network-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1222 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2010-2012 Richard Hughes + * Copyright (C) 2012 Thomas Bechtold + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include + +#include "cc-network-panel.h" + +#include "nm-remote-settings.h" +#include "nm-client.h" +#include "nm-device.h" +#include "nm-device-modem.h" + +#include "net-device.h" +#include "net-device-mobile.h" +#include "net-device-wifi.h" +#include "net-device-wired.h" +#include "net-object.h" +#include "net-proxy.h" +#include "net-vpn.h" + +#include "rfkill-glib.h" + +#include "panel-common.h" + +#include "network-dialogs.h" + +CC_PANEL_REGISTER (CcNetworkPanel, cc_network_panel) + +#define NETWORK_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_NETWORK_PANEL, CcNetworkPanelPrivate)) + +typedef enum { + OPERATION_NULL, + OPERATION_SHOW_DEVICE, + OPERATION_CREATE_WIFI, + OPERATION_CONNECT_HIDDEN, + OPERATION_CONNECT_8021X, + OPERATION_CONNECT_MOBILE +} CmdlineOperation; + +struct _CcNetworkPanelPrivate +{ + GCancellable *cancellable; + GtkBuilder *builder; + GtkWidget *treeview; + NMClient *client; + NMRemoteSettings *remote_settings; + gboolean updating_device; + guint add_header_widgets_idle; + guint nm_warning_idle; + guint refresh_idle; + + /* Killswitch stuff */ + GtkWidget *kill_switch_header; + CcRfkillGlib *rfkill; + GtkSwitch *rfkill_switch; + GHashTable *killswitches; + + /* wireless dialog stuff */ + CmdlineOperation arg_operation; + gchar *arg_device; + gchar *arg_access_point; + gboolean operation_done; +}; + +enum { + PANEL_DEVICES_COLUMN_ICON, + PANEL_DEVICES_COLUMN_TITLE, + PANEL_DEVICES_COLUMN_SORT, + PANEL_DEVICES_COLUMN_OBJECT, + PANEL_DEVICES_COLUMN_LAST +}; + +enum { + PROP_0, + PROP_ARGV +}; + +static NetObject *find_in_model_by_id (CcNetworkPanel *panel, const gchar *id); +static void handle_argv (CcNetworkPanel *panel); + +static void +cc_network_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static CmdlineOperation +cmdline_operation_from_string (const gchar *string) +{ + if (g_strcmp0 (string, "create-wifi") == 0) + return OPERATION_CREATE_WIFI; + if (g_strcmp0 (string, "connect-hidden-wifi") == 0) + return OPERATION_CONNECT_HIDDEN; + if (g_strcmp0 (string, "connect-8021x-wifi") == 0) + return OPERATION_CONNECT_8021X; + if (g_strcmp0 (string, "connect-3g") == 0) + return OPERATION_CONNECT_MOBILE; + if (g_strcmp0 (string, "show-device") == 0) + return OPERATION_SHOW_DEVICE; + + g_warning ("Invalid additional argument %s", string); + return OPERATION_NULL; +} + +static void +reset_command_line_args (CcNetworkPanel *self) +{ + self->priv->arg_operation = OPERATION_NULL; + g_clear_pointer (&self->priv->arg_device, g_free); + g_clear_pointer (&self->priv->arg_access_point, g_free); +} + +static gboolean +verify_argv (CcNetworkPanel *self, + const char **args) +{ + switch (self->priv->arg_operation) { + case OPERATION_CONNECT_MOBILE: + case OPERATION_CONNECT_8021X: + case OPERATION_SHOW_DEVICE: + if (self->priv->arg_device == NULL) { + g_warning ("Operation %s requires an object path", args[0]); + return FALSE; + } + default: + return TRUE; + } +} + +static void +cc_network_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + CcNetworkPanel *self = CC_NETWORK_PANEL (object); + CcNetworkPanelPrivate *priv = self->priv; + + switch (property_id) { + case PROP_ARGV: { + gchar **args; + + reset_command_line_args (self); + + args = g_value_get_boxed (value); + + if (args) { + g_debug ("Invoked with operation %s", args[0]); + + if (args[0]) + priv->arg_operation = cmdline_operation_from_string (args[0]); + if (args[0] && args[1]) + priv->arg_device = g_strdup (args[1]); + if (args[0] && args[1] && args[2]) + priv->arg_access_point = g_strdup (args[2]); + + if (verify_argv (self, (const char **) args) == FALSE) { + reset_command_line_args (self); + return; + } + + g_debug ("Calling handle_argv() after setting property"); + handle_argv (self); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_network_panel_dispose (GObject *object) +{ + CcNetworkPanelPrivate *priv = CC_NETWORK_PANEL (object)->priv; + + if (priv->cancellable != NULL) + g_cancellable_cancel (priv->cancellable); + + g_clear_object (&priv->cancellable); + g_clear_object (&priv->builder); + g_clear_object (&priv->client); + g_clear_object (&priv->remote_settings); + g_clear_object (&priv->kill_switch_header); + g_clear_object (&priv->rfkill); + g_clear_pointer (&priv->killswitches, g_hash_table_destroy); + priv->rfkill_switch = NULL; + + if (priv->refresh_idle != 0) { + g_source_remove (priv->refresh_idle); + priv->refresh_idle = 0; + } + if (priv->nm_warning_idle != 0) { + g_source_remove (priv->nm_warning_idle); + priv->nm_warning_idle = 0; + } + if (priv->add_header_widgets_idle != 0) { + g_source_remove (priv->add_header_widgets_idle); + priv->add_header_widgets_idle = 0; + } + + G_OBJECT_CLASS (cc_network_panel_parent_class)->dispose (object); +} + +static void +cc_network_panel_finalize (GObject *object) +{ + CcNetworkPanel *panel = CC_NETWORK_PANEL (object); + + reset_command_line_args (panel); + + G_OBJECT_CLASS (cc_network_panel_parent_class)->finalize (object); +} + +static const char * +cc_network_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/net"; +} + +static void +cc_network_panel_class_init (CcNetworkPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcNetworkPanelPrivate)); + + panel_class->get_help_uri = cc_network_panel_get_help_uri; + + object_class->get_property = cc_network_panel_get_property; + object_class->set_property = cc_network_panel_set_property; + object_class->dispose = cc_network_panel_dispose; + object_class->finalize = cc_network_panel_finalize; + + g_object_class_override_property (object_class, PROP_ARGV, "argv"); +} + +static NetObject * +get_selected_object (CcNetworkPanel *panel) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + NetObject *object = NULL; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return NULL; + } + + gtk_tree_model_get (model, &iter, + PANEL_DEVICES_COLUMN_OBJECT, &object, + -1); + + return object; +} + +static void +select_first_device (CcNetworkPanel *panel) +{ + GtkTreePath *path; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview)); + + /* select the first device */ + path = gtk_tree_path_new_from_string ("0"); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); +} + +static void +select_tree_iter (CcNetworkPanel *panel, GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview)); + + gtk_tree_selection_select_iter (selection, iter); +} + +static void +object_removed_cb (NetObject *object, CcNetworkPanel *panel) +{ + gboolean ret; + NetObject *object_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview)); + + /* remove device from model */ + model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + do { + gtk_tree_model_get (model, &iter, + PANEL_DEVICES_COLUMN_OBJECT, &object_tmp, + -1); + if (g_strcmp0 (net_object_get_id (object), + net_object_get_id (object_tmp)) == 0) { + g_object_unref (object_tmp); + if (!gtk_list_store_remove (GTK_LIST_STORE (model), &iter)) + gtk_tree_model_get_iter_first (model, &iter); + gtk_tree_selection_select_iter (selection, &iter); + + break; + } + g_object_unref (object_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static gboolean +handle_argv_for_device (CcNetworkPanel *panel, + NMDevice *device, + GtkTreeIter *iter) +{ + CcNetworkPanelPrivate *priv = panel->priv; + NMDeviceType type; + + if (priv->arg_operation == OPERATION_NULL) + return TRUE; + + type = nm_device_get_device_type (device); + + if (type == NM_DEVICE_TYPE_WIFI && + (priv->arg_operation == OPERATION_CREATE_WIFI || + priv->arg_operation == OPERATION_CONNECT_HIDDEN)) { + g_debug ("Selecting wifi device"); + select_tree_iter (panel, iter); + + if (priv->arg_operation == OPERATION_CREATE_WIFI) + cc_network_panel_create_wifi_network (panel, priv->client, priv->remote_settings); + else + cc_network_panel_connect_to_hidden_network (panel, priv->client, priv->remote_settings); + + reset_command_line_args (panel); /* done */ + return TRUE; + } else if (g_strcmp0 (nm_object_get_path (NM_OBJECT (device)), priv->arg_device) == 0) { + if (priv->arg_operation == OPERATION_CONNECT_MOBILE) { + cc_network_panel_connect_to_3g_network (panel, priv->client, priv->remote_settings, device); + + reset_command_line_args (panel); /* done */ + select_tree_iter (panel, iter); + return TRUE; + } else if (priv->arg_operation == OPERATION_CONNECT_8021X) { + cc_network_panel_connect_to_8021x_network (panel, priv->client, priv->remote_settings, device, priv->arg_access_point); + reset_command_line_args (panel); /* done */ + select_tree_iter (panel, iter); + return TRUE; + } + else if (priv->arg_operation == OPERATION_SHOW_DEVICE) { + select_tree_iter (panel, iter); + reset_command_line_args (panel); /* done */ + return TRUE; + } + } + + return FALSE; +} + +static void +handle_argv (CcNetworkPanel *panel) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ret; + + if (panel->priv->arg_operation == OPERATION_NULL) + return; + + model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) { + GObject *object_tmp; + NMDevice *device; + gboolean done = FALSE; + + gtk_tree_model_get (model, &iter, + PANEL_DEVICES_COLUMN_OBJECT, &object_tmp, + -1); + if (g_object_class_find_property (G_OBJECT_GET_CLASS (object_tmp), "nm-device") != NULL) { + g_object_get (object_tmp, "nm-device", &device, NULL); + done = handle_argv_for_device (panel, device, &iter); + g_object_unref (device); + } + + g_object_unref (object_tmp); + + if (done) + return; + + ret = gtk_tree_model_iter_next (model, &iter); + } + + g_debug ("Could not handle argv operation, no matching device yet?"); +} + +static gboolean +panel_add_device (CcNetworkPanel *panel, NMDevice *device) +{ + const gchar *title; + GtkListStore *liststore_devices; + GtkTreeIter iter; + NMDeviceType type; + NetDevice *net_device; + CcNetworkPanelPrivate *priv = panel->priv; + GtkNotebook *notebook; + GtkSizeGroup *size_group; + GType device_g_type; + + /* do we have an existing object with this id? */ + if (find_in_model_by_id (panel, nm_device_get_udi (device)) != NULL) + goto out; + + type = nm_device_get_device_type (device); + + g_debug ("device %s type %i path %s", + nm_device_get_udi (device), type, nm_object_get_path (NM_OBJECT (device))); + + /* map the NMDeviceType to the GType */ + switch (type) { + case NM_DEVICE_TYPE_ETHERNET: + device_g_type = NET_TYPE_DEVICE_WIRED; + break; + case NM_DEVICE_TYPE_MODEM: + device_g_type = NET_TYPE_DEVICE_MOBILE; + break; + case NM_DEVICE_TYPE_WIFI: + device_g_type = NET_TYPE_DEVICE_WIFI; + break; + default: + goto out; + } + + /* create device */ + title = panel_device_to_localized_string (device); + net_device = g_object_new (device_g_type, + "panel", panel, + "removable", FALSE, + "cancellable", panel->priv->cancellable, + "client", panel->priv->client, + "remote-settings", panel->priv->remote_settings, + "nm-device", device, + "id", nm_device_get_udi (device), + "title", title, + NULL); + + /* add as a panel */ + if (device_g_type != NET_TYPE_DEVICE) { + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder, + "notebook_types")); + size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder, + "sizegroup1")); + net_object_add_to_notebook (NET_OBJECT (net_device), + notebook, + size_group); + } + + liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (priv->builder, + "liststore_devices")); + g_signal_connect_object (net_device, "removed", + G_CALLBACK (object_removed_cb), panel, 0); + gtk_list_store_append (liststore_devices, &iter); + gtk_list_store_set (liststore_devices, + &iter, + PANEL_DEVICES_COLUMN_ICON, panel_device_to_icon_name (device), + PANEL_DEVICES_COLUMN_SORT, panel_device_to_sortable_string (device), + PANEL_DEVICES_COLUMN_TITLE, title, + PANEL_DEVICES_COLUMN_OBJECT, net_device, + -1); + +out: + return FALSE; +} + +static void +panel_remove_device (CcNetworkPanel *panel, NMDevice *device) +{ + gboolean ret; + NetObject *object_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + + /* remove device from model */ + model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + do { + gtk_tree_model_get (model, &iter, + PANEL_DEVICES_COLUMN_OBJECT, &object_tmp, + -1); + if (g_strcmp0 (net_object_get_id (object_tmp), + nm_device_get_udi (device)) == 0) { + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + g_object_unref (object_tmp); + break; + } + g_object_unref (object_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +panel_add_devices_columns (CcNetworkPanel *panel, GtkTreeView *treeview) +{ + CcNetworkPanelPrivate *priv = panel->priv; + GtkCellRenderer *renderer; + GtkListStore *liststore_devices; + GtkTreeViewColumn *column; + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", gtk_icon_size_from_name ("cc-sidebar-list"), NULL); + gtk_cell_renderer_set_padding (renderer, 4, 4); + + column = gtk_tree_view_column_new_with_attributes ("icon", renderer, + "icon-name", PANEL_DEVICES_COLUMN_ICON, + NULL); + gtk_tree_view_append_column (treeview, column); + + /* column for text */ + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "wrap-mode", PANGO_WRAP_WORD, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes ("title", renderer, + "markup", PANEL_DEVICES_COLUMN_TITLE, + NULL); + gtk_tree_view_column_set_sort_column_id (column, PANEL_DEVICES_COLUMN_SORT); + liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (priv->builder, + "liststore_devices")); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (liststore_devices), + PANEL_DEVICES_COLUMN_SORT, + GTK_SORT_ASCENDING); + gtk_tree_view_append_column (treeview, column); + gtk_tree_view_column_set_expand (column, TRUE); +} + +static void +nm_devices_treeview_clicked_cb (GtkTreeSelection *selection, CcNetworkPanel *panel) +{ + CcNetworkPanelPrivate *priv = panel->priv; + const gchar *id_tmp; + const gchar *needle; + GList *l; + GList *panels = NULL; + GtkNotebook *notebook; + GtkTreeIter iter; + GtkTreeModel *model; + GtkWidget *widget; + guint i = 0; + NetObject *object = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + g_debug ("no row selected"); + goto out; + } + + /* find the widget in the notebook that matches the object ID */ + object = get_selected_object (panel); + needle = net_object_get_id (object); + notebook = GTK_NOTEBOOK (gtk_builder_get_object (priv->builder, + "notebook_types")); + panels = gtk_container_get_children (GTK_CONTAINER (notebook)); + for (l = panels; l != NULL; l = l->next) { + widget = GTK_WIDGET (l->data); + id_tmp = g_object_get_data (G_OBJECT (widget), "NetObject::id"); + if (g_strcmp0 (needle, id_tmp) == 0) { + gtk_notebook_set_current_page (notebook, i); + + /* object is deletable? */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "remove_toolbutton")); + gtk_widget_set_sensitive (widget, + net_object_get_removable (object)); + break; + } + i++; + } +out: + g_list_free (panels); +} + +static void +panel_add_proxy_device (CcNetworkPanel *panel) +{ + gchar *title; + GtkListStore *liststore_devices; + GtkTreeIter iter; + NetProxy *proxy; + GtkNotebook *notebook; + GtkSizeGroup *size_group; + + /* add proxy to notebook */ + proxy = net_proxy_new (); + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder, + "notebook_types")); + size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder, + "sizegroup1")); + net_object_add_to_notebook (NET_OBJECT (proxy), + notebook, + size_group); + + /* add proxy to device list */ + liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + title = g_strdup_printf ("%s", _("Network proxy")); + gtk_list_store_append (liststore_devices, &iter); + gtk_list_store_set (liststore_devices, + &iter, + PANEL_DEVICES_COLUMN_ICON, "preferences-system-network", + PANEL_DEVICES_COLUMN_TITLE, title, + PANEL_DEVICES_COLUMN_SORT, "9", + PANEL_DEVICES_COLUMN_OBJECT, proxy, + -1); + g_free (title); + g_object_unref (proxy); +} + +static void +cc_network_panel_notify_enable_active_cb (GtkSwitch *sw, + GParamSpec *pspec, + CcNetworkPanel *panel) +{ + gboolean enable; + struct rfkill_event event; + + enable = gtk_switch_get_active (sw); + g_debug ("Setting killswitch to %d", enable); + + memset (&event, 0, sizeof(event)); + event.op = RFKILL_OP_CHANGE_ALL; + event.type = RFKILL_TYPE_ALL; + event.soft = enable ? 1 : 0; + if (cc_rfkill_glib_send_event (panel->priv->rfkill, &event) < 0) + g_warning ("Setting the killswitch %s failed", enable ? "on" : "off"); +} + +static void +connection_state_changed (NMActiveConnection *c, GParamSpec *pspec, CcNetworkPanel *panel) +{ +} + +static void +active_connections_changed (NMClient *client, GParamSpec *pspec, gpointer user_data) +{ + CcNetworkPanel *panel = user_data; + const GPtrArray *connections; + int i, j; + + g_debug ("Active connections changed:"); + connections = nm_client_get_active_connections (client); + for (i = 0; connections && (i < connections->len); i++) { + NMActiveConnection *connection; + const GPtrArray *devices; + + connection = g_ptr_array_index (connections, i); + g_debug (" %s", nm_object_get_path (NM_OBJECT (connection))); + devices = nm_active_connection_get_devices (connection); + for (j = 0; devices && j < devices->len; j++) + g_debug (" %s", nm_device_get_udi (g_ptr_array_index (devices, j))); + if (NM_IS_VPN_CONNECTION (connection)) + g_debug (" VPN base connection: %s", nm_active_connection_get_specific_object (connection)); + + if (g_object_get_data (G_OBJECT (connection), "has-state-changed-handler") == NULL) { + g_signal_connect_object (connection, "notify::state", + G_CALLBACK (connection_state_changed), panel, 0); + g_object_set_data (G_OBJECT (connection), "has-state-changed-handler", GINT_TO_POINTER (TRUE)); + } + } +} + +static void +device_added_cb (NMClient *client, NMDevice *device, CcNetworkPanel *panel) +{ + g_debug ("New device added"); + panel_add_device (panel, device); +} + +static void +device_removed_cb (NMClient *client, NMDevice *device, CcNetworkPanel *panel) +{ + g_debug ("Device removed"); + panel_remove_device (panel, device); +} + +static void +manager_running (NMClient *client, GParamSpec *pspec, gpointer user_data) +{ + const GPtrArray *devices; + int i; + NMDevice *device_tmp; + GtkListStore *liststore_devices; + gboolean selected = FALSE; + CcNetworkPanel *panel = CC_NETWORK_PANEL (user_data); + + /* clear all devices we added */ + if (!nm_client_get_manager_running (client)) { + g_debug ("NM disappeared"); + liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + gtk_list_store_clear (liststore_devices); + panel_add_proxy_device (panel); + goto out; + } + + g_debug ("coldplugging devices"); + devices = nm_client_get_devices (client); + if (devices == NULL) { + g_debug ("No devices to add"); + return; + } + for (i = 0; i < devices->len; i++) { + device_tmp = g_ptr_array_index (devices, i); + selected = panel_add_device (panel, device_tmp) || selected; + } +out: + if (!selected) { + /* select the first device */ + select_first_device (panel); + } + + g_debug ("Calling handle_argv() after cold-plugging devices"); + handle_argv (panel); +} + +static NetObject * +find_in_model_by_id (CcNetworkPanel *panel, const gchar *id) +{ + gboolean ret; + NetObject *object_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + NetObject *object = NULL; + + /* find in model */ + model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + goto out; + + /* get the other elements */ + ret = FALSE; + do { + gtk_tree_model_get (model, &iter, + PANEL_DEVICES_COLUMN_OBJECT, &object_tmp, + -1); + if (object_tmp != NULL) { + g_debug ("got %s", net_object_get_id (object_tmp)); + if (g_strcmp0 (net_object_get_id (object_tmp), id) == 0) + object = object_tmp; + g_object_unref (object_tmp); + } + } while (object == NULL && gtk_tree_model_iter_next (model, &iter)); +out: + return object; +} + +static void +panel_add_vpn_device (CcNetworkPanel *panel, NMConnection *connection) +{ + gchar *title; + gchar *title_markup; + GtkListStore *liststore_devices; + GtkTreeIter iter; + NetVpn *net_vpn; + const gchar *id; + GtkNotebook *notebook; + GtkSizeGroup *size_group; + + /* does already exist */ + id = nm_connection_get_path (connection); + if (find_in_model_by_id (panel, id) != NULL) + return; + + /* add as a virtual object */ + net_vpn = g_object_new (NET_TYPE_VPN, + "panel", panel, + "removable", TRUE, + "id", id, + "connection", connection, + "client", panel->priv->client, + NULL); + g_signal_connect_object (net_vpn, "removed", + G_CALLBACK (object_removed_cb), panel, 0); + + /* add as a panel */ + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->priv->builder, + "notebook_types")); + size_group = GTK_SIZE_GROUP (gtk_builder_get_object (panel->priv->builder, + "sizegroup1")); + net_object_add_to_notebook (NET_OBJECT (net_vpn), + notebook, + size_group); + + liststore_devices = GTK_LIST_STORE (gtk_builder_get_object (panel->priv->builder, + "liststore_devices")); + title = g_strdup_printf (_("%s VPN"), nm_connection_get_id (connection)); + title_markup = g_strdup (title); + + net_object_set_title (NET_OBJECT (net_vpn), title); + gtk_list_store_append (liststore_devices, &iter); + gtk_list_store_set (liststore_devices, + &iter, + PANEL_DEVICES_COLUMN_ICON, "network-vpn", + PANEL_DEVICES_COLUMN_TITLE, title_markup, + PANEL_DEVICES_COLUMN_SORT, "5", + PANEL_DEVICES_COLUMN_OBJECT, net_vpn, + -1); + g_free (title); + g_free (title_markup); +} + +static void +add_connection (CcNetworkPanel *panel, + NMConnection *connection) +{ + NMSettingConnection *s_con; + const gchar *type; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, + NM_TYPE_SETTING_CONNECTION)); + type = nm_setting_connection_get_connection_type (s_con); + if (g_strcmp0 (type, "vpn") != 0) + return; + g_debug ("add %s/%s remote connection: %s", + type, g_type_name_from_instance ((GTypeInstance*)connection), + nm_connection_get_path (connection)); + panel_add_vpn_device (panel, connection); +} + +static void +notify_new_connection_cb (NMRemoteSettings *settings, + NMRemoteConnection *connection, + CcNetworkPanel *panel) +{ + add_connection (panel, NM_CONNECTION (connection)); +} + +static void +notify_connections_read_cb (NMRemoteSettings *settings, + CcNetworkPanel *panel) +{ + GSList *list, *iter; + NMConnection *connection; + + list = nm_remote_settings_list_connections (settings); + g_debug ("%p has %i remote connections", + panel, g_slist_length (list)); + for (iter = list; iter; iter = g_slist_next (iter)) { + connection = NM_CONNECTION (iter->data); + add_connection (panel, connection); + } +} + +static gboolean +display_version_warning_idle (CcNetworkPanel *panel) +{ + GtkWidget *dialog; + GtkWidget *image; + GtkWindow *window; + const char *message; + + /* TRANSLATORS: the user is running a NM that is not API compatible */ + message = _("The system network services are not compatible with this version."); + + window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (panel))); + dialog = gtk_message_dialog_new (window, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", + message); + image = gtk_image_new_from_icon_name ("computer-fail", GTK_ICON_SIZE_DIALOG); + gtk_widget_show (image); + gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return FALSE; +} + +static gboolean +panel_check_network_manager_version (CcNetworkPanel *panel) +{ + const gchar *version; + gchar **split = NULL; + guint major = 0; + guint micro = 0; + guint minor = 0; + gboolean ret = TRUE; + + /* parse running version */ + version = nm_client_get_version (panel->priv->client); + if (version != NULL) { + split = g_strsplit (version, ".", -1); + major = atoi (split[0]); + minor = atoi (split[1]); + micro = atoi (split[2]); + } + + /* is it too new or old */ + if (major > 0 || major > 9 || (minor <= 8 && micro < 992)) { + ret = FALSE; + + /* do modal dialog in idle so we don't block startup */ + panel->priv->nm_warning_idle = g_idle_add ((GSourceFunc)display_version_warning_idle, panel); + } + + g_strfreev (split); + return ret; +} + +static void +add_connection_cb (GtkToolButton *button, CcNetworkPanel *panel) +{ + GtkWidget *dialog; + gint response; + + dialog = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "connection_type_dialog")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (panel)))); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_hide (dialog); + + if (response == GTK_RESPONSE_OK) { + GtkComboBox *combo; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *cmdline; + GError *error; + + combo = GTK_COMBO_BOX (gtk_builder_get_object (panel->priv->builder, + "connection_type_combo")); + model = gtk_combo_box_get_model (combo); + gtk_combo_box_get_active_iter (combo, &iter); + type = NULL; + gtk_tree_model_get (model, &iter, 1, &type, -1); + + cmdline = g_strdup_printf ("nm-connection-editor --create --type %s", type); + g_debug ("Launching '%s'\n", cmdline); + + error = NULL; + if (!g_spawn_command_line_async (cmdline, &error)) { + g_warning ("Failed to launch nm-connection-editor: %s", error->message); + g_error_free (error); + } + g_free (cmdline); + g_free (type); + } +} + +static void +remove_connection (GtkToolButton *button, CcNetworkPanel *panel) +{ + NetObject *object; + + /* get current device */ + object = get_selected_object (panel); + if (object == NULL) + return; + + /* delete the object */ + net_object_delete (object); +} + +static void +on_toplevel_map (GtkWidget *widget, + CcNetworkPanel *panel) +{ + gboolean ret; + + /* is the user compiling against a new version, but running an + * old daemon version? */ + ret = panel_check_network_manager_version (panel); + if (ret) { + manager_running (panel->priv->client, NULL, panel); + } else { + /* just select the proxy settings */ + select_first_device (panel); + } +} + +static void +rfkill_changed (CcRfkillGlib *rfkill, + GList *events, + CcNetworkPanel *panel) +{ + gboolean enabled; + GList *l; + GHashTableIter iter; + gpointer key, value; + + enabled = TRUE; + + for (l = events; l != NULL; l = l->next) { + struct rfkill_event *event = l->data; + + if (event->op == RFKILL_OP_ADD) + g_hash_table_insert (panel->priv->killswitches, + GINT_TO_POINTER (event->idx), + GINT_TO_POINTER (event->soft || event->hard)); + else if (event->op == RFKILL_OP_CHANGE) + g_hash_table_insert (panel->priv->killswitches, + GINT_TO_POINTER (event->idx), + GINT_TO_POINTER (event->soft || event->hard)); + else if (event->op == RFKILL_OP_DEL) + g_hash_table_remove (panel->priv->killswitches, + GINT_TO_POINTER (event->idx)); + } + + g_hash_table_iter_init (&iter, panel->priv->killswitches); + while (g_hash_table_iter_next (&iter, &key, &value)) { + int idx, state; + + idx = GPOINTER_TO_INT (key); + state = GPOINTER_TO_INT (value); + g_debug ("Killswitch %d is %s", idx, state ? "enabled" : "disabled"); + + /* A single device that's enabled? airplane mode is off */ + if (state == FALSE) { + enabled = FALSE; + break; + } + } + + if (enabled != gtk_switch_get_active (panel->priv->rfkill_switch)) { + g_signal_handlers_block_by_func (panel->priv->rfkill_switch, + cc_network_panel_notify_enable_active_cb, + panel); + gtk_switch_set_active (panel->priv->rfkill_switch, enabled); + g_signal_handlers_unblock_by_func (panel->priv->rfkill_switch, + cc_network_panel_notify_enable_active_cb, + panel); + } +} + +static gboolean +network_add_shell_header_widgets_cb (gpointer user_data) +{ + CcNetworkPanel *panel = CC_NETWORK_PANEL (user_data); + GtkWidget *box; + GtkWidget *label; + GtkWidget *widget; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); + /* TRANSLATORS: this is to disable the radio hardware in the + * network panel */ + label = gtk_label_new_with_mnemonic (_("Air_plane Mode")); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); + gtk_widget_set_visible (label, TRUE); + widget = gtk_switch_new (); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); + gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0); + gtk_widget_show_all (box); + panel->priv->rfkill_switch = GTK_SWITCH (widget); + cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (panel)), box); + panel->priv->kill_switch_header = g_object_ref (box); + + panel->priv->killswitches = g_hash_table_new (g_direct_hash, g_direct_equal); + panel->priv->rfkill = cc_rfkill_glib_new (); + g_signal_connect (G_OBJECT (panel->priv->rfkill), "changed", + G_CALLBACK (rfkill_changed), panel); + if (cc_rfkill_glib_open (panel->priv->rfkill) < 0) + gtk_widget_hide (box); + + g_signal_connect (panel->priv->rfkill_switch, "notify::active", + G_CALLBACK (cc_network_panel_notify_enable_active_cb), + panel); + + return FALSE; +} + +static void +cc_network_panel_init (CcNetworkPanel *panel) +{ + DBusGConnection *bus = NULL; + GError *error = NULL; + GtkStyleContext *context; + GtkTreeSelection *selection; + GtkWidget *widget; + GtkWidget *toplevel; + + panel->priv = NETWORK_PANEL_PRIVATE (panel); + + panel->priv->builder = gtk_builder_new (); + gtk_builder_add_from_file (panel->priv->builder, + GNOMECC_UI_DIR "/network.ui", + &error); + if (error != NULL) { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + panel->priv->cancellable = g_cancellable_new (); + + panel->priv->treeview = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "treeview_devices")); + panel_add_devices_columns (panel, GTK_TREE_VIEW (panel->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->priv->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (selection, "changed", + G_CALLBACK (nm_devices_treeview_clicked_cb), panel); + + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "devices_scrolledwindow")); + gtk_widget_set_size_request (widget, 200, -1); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "devices_toolbar")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + /* add the virtual proxy device */ + panel_add_proxy_device (panel); + + /* use NetworkManager client */ + panel->priv->client = nm_client_new (); + g_signal_connect (panel->priv->client, "notify::" NM_CLIENT_MANAGER_RUNNING, + G_CALLBACK (manager_running), panel); + g_signal_connect (panel->priv->client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS, + G_CALLBACK (active_connections_changed), panel); + g_signal_connect (panel->priv->client, "device-added", + G_CALLBACK (device_added_cb), panel); + g_signal_connect (panel->priv->client, "device-removed", + G_CALLBACK (device_removed_cb), panel); + + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "add_toolbutton")); + g_signal_connect (widget, "clicked", + G_CALLBACK (add_connection_cb), panel); + + /* disable for now, until we actually show removable connections */ + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "remove_toolbutton")); + g_signal_connect (widget, "clicked", + G_CALLBACK (remove_connection), panel); + + /* add remote settings such as VPN settings as virtual devices */ + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Error connecting to system D-Bus: %s", + error->message); + g_error_free (error); + } + panel->priv->remote_settings = nm_remote_settings_new (bus); + g_signal_connect (panel->priv->remote_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ, + G_CALLBACK (notify_connections_read_cb), panel); + g_signal_connect (panel->priv->remote_settings, NM_REMOTE_SETTINGS_NEW_CONNECTION, + G_CALLBACK (notify_new_connection_cb), panel); + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (panel)); + g_signal_connect_after (toplevel, "map", G_CALLBACK (on_toplevel_map), panel); + + /* hide implementation details */ + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "notebook_types")); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); + + widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, + "vbox1")); + gtk_widget_reparent (widget, (GtkWidget *) panel); + + /* add kill switch widgets when dialog activated */ + panel->priv->add_header_widgets_idle = g_idle_add (network_add_shell_header_widgets_cb, panel); +} + +void +cc_network_panel_register (GIOModule *module) +{ + cc_network_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_NETWORK_PANEL, + "network", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/online-accounts/cc-online-accounts-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/online-accounts/cc-online-accounts-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/online-accounts/cc-online-accounts-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/online-accounts/cc-online-accounts-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,792 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2011, 2012 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include +#include + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#include +#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE +#include + +#include "cc-online-accounts-panel.h" + +#include "cc-online-accounts-add-account-dialog.h" +#include "cc-online-accounts-model.h" + +typedef struct _GoaPanelClass GoaPanelClass; + +struct _GoaPanel +{ + CcPanel parent_instance; + + GtkBuilder *builder; + + GoaClient *client; + + GoaPanelAccountsModel *accounts_model; + + GtkWidget *toolbar; + GtkWidget *toolbar_add_button; + GtkWidget *toolbar_remove_button; + GtkWidget *accounts_treeview; + GtkWidget *accounts_vbox; +}; + +struct _GoaPanelClass +{ + CcPanelClass parent_class; +}; + +static void on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data); +static void on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data); + +static void on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data); + +static void on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data); +static void on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data); + +static void on_add_button_clicked (GtkButton *button, + gpointer user_data); + +static void on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static gboolean select_account_by_id (GoaPanel *panel, + const gchar *account_id); + +CC_PANEL_REGISTER (GoaPanel, goa_panel); + +enum { + PROP_0, + PROP_ARGV +}; + +static void +goa_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + case PROP_ARGV: + { + gchar **args; + + args = g_value_get_boxed (value); + + if (args != NULL && *args != '\0') + select_account_by_id (GOA_PANEL (object), args[0]); + return; + } + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +goa_panel_finalize (GObject *object) +{ + GoaPanel *panel = GOA_PANEL (object); + + if (panel->accounts_model != NULL) + g_clear_object (&panel->accounts_model); + + if (panel->client != NULL) + g_object_unref (panel->client); + g_object_unref (panel->builder); + + G_OBJECT_CLASS (goa_panel_parent_class)->finalize (object); +} + +static void +goa_panel_init (GoaPanel *panel) +{ + GtkWidget *button; + GtkWidget *w; + GError *error; + GtkStyleContext *context; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + + panel->builder = gtk_builder_new (); + error = NULL; + if (gtk_builder_add_from_file (panel->builder, + GNOMECC_UI_DIR "/online-accounts.ui", + &error) == 0) + { + goa_warning ("Error loading UI file: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + g_error_free (error); + goto out; + } + + panel->toolbar = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbar")); + panel->toolbar_add_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-add")); + g_signal_connect (panel->toolbar_add_button, + "clicked", + G_CALLBACK (on_toolbar_add_button_clicked), + panel); + panel->toolbar_remove_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-remove")); + g_signal_connect (panel->toolbar_remove_button, + "clicked", + G_CALLBACK (on_toolbar_remove_button_clicked), + panel); + + context = gtk_widget_get_style_context (GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-scrolledwindow"))); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + context = gtk_widget_get_style_context (panel->toolbar); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + panel->accounts_treeview = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-treeview")); + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + "changed", + G_CALLBACK (on_tree_view_selection_changed), + panel); + + button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-button-add")); + g_signal_connect (button, + "clicked", + G_CALLBACK (on_add_button_clicked), + panel); + + panel->accounts_vbox = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-vbox")); + + /* TODO: probably want to avoid _sync() ... */ + error = NULL; + panel->client = goa_client_new_sync (NULL /* GCancellable */, &error); + if (panel->client == NULL) + { + goa_warning ("Error getting a GoaClient: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_set_sensitive (w, FALSE); + g_error_free (error); + goto out; + } + g_signal_connect (panel->client, + "account-changed", + G_CALLBACK (on_account_changed), + panel); + + panel->accounts_model = goa_panel_accounts_model_new (panel->client); + gtk_tree_view_set_model (GTK_TREE_VIEW (panel->accounts_treeview), GTK_TREE_MODEL (panel->accounts_model)); + g_signal_connect (panel->accounts_model, "row-deleted", G_CALLBACK (on_model_row_deleted), panel); + g_signal_connect (panel->accounts_model, "row-inserted", G_CALLBACK (on_model_row_inserted), panel); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (panel->accounts_treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "gicon", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "ellipsize", PANGO_ELLIPSIZE_END, + "ellipsize-set", TRUE, + "width-chars", 30, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "markup", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_MARKUP, + NULL); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_end (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "icon-name", "dialog-error-symbolic", + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "visible", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ATTENTION_NEEDED, + NULL); + + /* Select the first row, if any */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (panel->accounts_model), + &iter)) + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + &iter); + + out: + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_reparent (w, GTK_WIDGET (panel)); + gtk_widget_show_all (w); +} + +static const char * +goa_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/accounts"; +} + +static void +goa_panel_class_init (GoaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = goa_panel_get_help_uri; + + object_class->set_property = goa_panel_set_property; + object_class->finalize = goa_panel_finalize; + + g_object_class_override_property (object_class, PROP_ARGV, "argv"); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +goa_panel_register (GIOModule *module) +{ + goa_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + GOA_TYPE_PANEL, + "online-accounts", + 0); +} + +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + goa_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +show_page (GoaPanel *panel, + gint page_num) +{ + GtkNotebook *notebook; + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->builder, "accounts-notebook")); + gtk_notebook_set_current_page (notebook, page_num); +} + +static void +show_page_nothing_selected (GoaPanel *panel) +{ + GtkWidget *box; + GtkWidget *label; + + show_page (panel, 0); + + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, FALSE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_show (label); +} + +static void +on_info_bar_response (GtkInfoBar *info_bar, + gint response_id, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaProvider *provider; + const gchar *provider_type; + GoaAccount *account; + GoaObject *object; + GtkWindow *parent; + GError *error; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); + + error = NULL; + if (!goa_provider_refresh_account (provider, + panel->client, + object, + parent, + &error)) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error logging into the account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + g_object_unref (provider); + g_object_unref (object); + } +} + +static void +show_page_account (GoaPanel *panel, + GoaObject *object) +{ + GList *children; + GList *l; + GtkWidget *box; + GtkWidget *grid; + GtkWidget *left_grid; + GtkWidget *right_grid; + GtkWidget *bar; + GtkWidget *label; + GoaProvider *provider; + GoaAccount *account; + const gchar *provider_type; + + provider = NULL; + + show_page (panel, 1); + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, TRUE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_hide (label); + + /* Out with the old */ + children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_vbox)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (panel->accounts_vbox), GTK_WIDGET (l->data)); + g_list_free (children); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + /* And in with the new */ + if (goa_account_get_attention_needed (account)) + { + bar = gtk_info_bar_new (); + label = gtk_label_new (_("Expired credentials. Please log in again.")); + gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label); + if (provider != NULL) + gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("_Log In"), GTK_RESPONSE_OK); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), bar, FALSE, TRUE, 0); + g_signal_connect (bar, "response", G_CALLBACK (on_info_bar_response), panel); + } + + left_grid = gtk_grid_new (); + gtk_widget_set_halign (left_grid, GTK_ALIGN_END); + gtk_widget_set_hexpand (left_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (left_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (left_grid), 0); + + right_grid = gtk_grid_new (); + gtk_widget_set_hexpand (right_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (right_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (right_grid), 0); + + if (provider != NULL) + { + goa_provider_show_account (provider, + panel->client, + object, + GTK_BOX (panel->accounts_vbox), + GTK_GRID (left_grid), + GTK_GRID (right_grid)); + } + + grid = gtk_grid_new (); + gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL); + gtk_grid_set_column_spacing (GTK_GRID (grid), 12); + gtk_container_add (GTK_CONTAINER (grid), left_grid); + gtk_container_add (GTK_CONTAINER (grid), right_grid); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), grid, FALSE, TRUE, 0); + + gtk_widget_show_all (panel->accounts_vbox); + + if (provider != NULL) + g_object_unref (provider); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +select_account_by_id (GoaPanel *panel, + const gchar *account_id) +{ + GoaObject *goa_object = NULL; + GtkTreeIter iter; + gboolean iter_set = FALSE; + + goa_object = goa_client_lookup_by_id (panel->client, account_id); + if (goa_object != NULL) + { + iter_set = goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, + goa_object, + &iter); + g_object_unref (goa_object); + } + + if (iter_set) + { + GtkTreeView *tree_view; + GtkTreeSelection *selection; + + tree_view = GTK_TREE_VIEW (panel->accounts_treeview); + selection = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_select_iter (selection, &iter); + } + + return iter_set; +} + +static void +on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GoaObject *object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + show_page_account (panel, object); + g_object_unref (object); + } + else + { + show_page_nothing_selected (panel); + } +} + +static void +on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *selected_object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &selected_object, + -1); + if (selected_object == object) + show_page_account (panel, selected_object); + g_object_unref (selected_object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_model_row_changed (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GtkTreeSelection *selection = GTK_TREE_SELECTION (user_data); + + gtk_tree_selection_select_iter (selection, iter); + g_signal_handlers_disconnect_by_func (tree_model, G_CALLBACK (on_model_row_changed), user_data); +} + +static void +on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + GtkTreeSelection *selection; + + if (!gtk_tree_model_get_iter (tree_model, &iter, path)) + { + if (!gtk_tree_path_prev (path)) + return; + } + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + gtk_tree_selection_select_path (selection, path); +} + +static void +on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + if (gtk_tree_selection_get_selected (selection, NULL, NULL)) + return; + + /* An empty row has been inserted and is going to be filled in, so + * we expect selection to stay valid. + */ + g_signal_connect (tree_model, "row-changed", G_CALLBACK (on_model_row_changed), selection); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GoaPanel *panel; +} AddAccountData; + +static void +get_all_providers_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + AddAccountData *data = user_data; + GtkWindow *parent; + GtkWidget *dialog; + gint response; + GList *providers; + GList *l; + GoaObject *object; + GError *error; + + providers = NULL; + + providers = NULL; + if (!goa_provider_get_all_finish (&providers, res, NULL)) + goto out; + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (data->panel)))); + + dialog = goa_panel_add_account_dialog_new (data->panel->client); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + for (l = providers; l != NULL; l = l->next) + { + GoaProvider *provider; + + provider = GOA_PROVIDER (l->data); + goa_panel_add_account_dialog_add_provider (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), provider); + } + + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + if (response != GTK_RESPONSE_OK) + { + gtk_widget_destroy (dialog); + goto out; + } + + error = NULL; + object = goa_panel_add_account_dialog_get_account (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), &error); + gtk_widget_destroy (dialog); + + /* We might have an object even when error is set. + * eg., if we failed to store the credentials in the keyring. + */ + + if (object != NULL) + { + GtkTreeIter iter; + /* navigate to newly created object */ + if (goa_panel_accounts_model_get_iter_for_object (data->panel->accounts_model, + object, + &iter)) + { + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->panel->accounts_treeview)), + &iter); + } + g_object_unref (object); + } + + if (error != NULL) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error creating account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + + out: + g_list_foreach (providers, (GFunc) g_object_unref, NULL); + g_list_free (providers); + g_clear_object (&data->panel); + g_slice_free (AddAccountData, data); +} + +static void +add_account (GoaPanel *panel) +{ + AddAccountData *data; + + data = g_slice_new0 (AddAccountData); + data->panel = g_object_ref_sink (panel); + goa_provider_get_all (get_all_providers_cb, data); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} + +static void +remove_account_cb (GoaAccount *account, + GAsyncResult *res, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GError *error; + + error = NULL; + if (!goa_account_call_remove_finish (account, res, &error)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error removing account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } + g_object_unref (panel); +} + +static void +on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *object; + GtkWidget *dialog; + gint response; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + _("Are you sure you want to remove the account?")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("This will not remove the account on the server.")); + gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Remove"), GTK_RESPONSE_OK); + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (response == GTK_RESPONSE_OK) + { + goa_account_call_remove (goa_object_peek_account (object), + NULL, /* GCancellable */ + (GAsyncReadyCallback) remove_account_cb, + g_object_ref (panel)); + } + g_object_unref (object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_add_button_clicked (GtkButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/power/cc-power-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/power/cc-power-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/power/cc-power-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/power/cc-power-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1122 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2010 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include + +#include "cc-power-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcPowerPanel, cc_power_panel) + +#define POWER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_POWER_PANEL, CcPowerPanelPrivate)) + +struct _CcPowerPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + UpClient *up_client; + GtkWidget *levelbar_primary; +}; + +enum +{ + ACTION_MODEL_TEXT, + ACTION_MODEL_VALUE, + ACTION_MODEL_SENSITIVE +}; + +static void +cc_power_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_dispose (GObject *object) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (object)->priv; + + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + if (priv->up_client != NULL) + { + g_object_unref (priv->up_client); + priv->up_client = NULL; + } + + G_OBJECT_CLASS (cc_power_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcPowerPanel *panel) +{ +} + +static const char * +cc_power_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/power"; +} + +static void +cc_power_panel_class_init (CcPowerPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcPowerPanelPrivate)); + + object_class->get_property = cc_power_panel_get_property; + object_class->set_property = cc_power_panel_set_property; + object_class->dispose = cc_power_panel_dispose; + + panel_class->get_help_uri = cc_power_panel_get_help_uri; +} + +static gchar * +get_timestring (guint64 time_secs) +{ + gchar* timestring = NULL; + gint hours; + gint minutes; + + /* Add 0.5 to do rounding */ + minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); + + if (minutes == 0) + { + timestring = g_strdup (_("Unknown time")); + return timestring; + } + + if (minutes < 60) + { + timestring = g_strdup_printf (ngettext ("%i minute", + "%i minutes", + minutes), minutes); + return timestring; + } + + hours = minutes / 60; + minutes = minutes % 60; + + if (minutes == 0) + { + timestring = g_strdup_printf (ngettext ( + "%i hour", + "%i hours", + hours), hours); + return timestring; + } + + /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" + * Swap order with "%2$s %2$i %1$s %1$i if needed */ + timestring = g_strdup_printf (_("%i %s %i %s"), + hours, ngettext ("hour", "hours", hours), + minutes, ngettext ("minute", "minutes", minutes)); + return timestring; +} + +static void +set_device_battery_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* clear the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_hide (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Charging - %s until fully charged"), + time_string); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low battery, %s remaining"), + time_string); + /* show the warning */ + gtk_widget_show (widget); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using battery power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Using battery power")); + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Empty")); + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device until we stumble upon the device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_ups_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* always show the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_show (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low UPS, %s remaining"), + time_string); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using UPS power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Caution low UPS")); + } + else + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Using UPS power")); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device as extra UPS devices are not possible */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_battery_additional (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + GtkWidget *widget; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + NULL, /* percentage */ + &state, + NULL /* time */); + + /* set the description */ + switch (state) + { + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is empty")); + break; + default: + break; + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_addon")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the addon device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_show (widget); +out: + g_free (details); +} + +static void +add_device_secondary (CcPowerPanel *panel, + GVariant *device, + guint *secondary_devices_cnt) +{ + CcPowerPanelPrivate *priv = panel->priv; + const gchar *icon_name = NULL; + gdouble percentage; + guint64 time; + UpDeviceKind kind; + UpDeviceState state; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *widget; + GString *status; + GString *description; + gboolean show_caution = FALSE; + + g_variant_get (device, + "(susdut)", + NULL, + &kind, + NULL, + &percentage, + &state, + &time); + + switch (kind) + { + case UP_DEVICE_KIND_UPS: + icon_name = "uninterruptible-power-supply"; + show_caution = TRUE; + break; + case UP_DEVICE_KIND_MOUSE: + icon_name = "input-mouse"; + break; + case UP_DEVICE_KIND_KEYBOARD: + icon_name = "input-keyboard"; + break; + case UP_DEVICE_KIND_TABLET: + icon_name = "input-tablet"; + break; + case UP_DEVICE_KIND_PDA: + icon_name = "pda"; + break; + case UP_DEVICE_KIND_PHONE: + icon_name = "phone"; + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + icon_name = "multimedia-player"; + break; + case UP_DEVICE_KIND_COMPUTER: + icon_name = "computer"; + show_caution = TRUE; + break; + default: + icon_name = "battery"; + break; + } + + switch (kind) + { + case UP_DEVICE_KIND_MOUSE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless mouse")); + break; + case UP_DEVICE_KIND_KEYBOARD: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless keyboard")); + break; + case UP_DEVICE_KIND_UPS: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Uninterruptible power supply")); + break; + case UP_DEVICE_KIND_PDA: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Personal digital assistant")); + break; + case UP_DEVICE_KIND_PHONE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Cellphone")); + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Media player")); + break; + case UP_DEVICE_KIND_TABLET: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Tablet")); + break; + case UP_DEVICE_KIND_COMPUTER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Computer")); + break; + default: + /* TRANSLATORS: secondary battery, misc */ + description = g_string_new (_("Battery")); + break; + } + g_string_prepend (description, ""); + g_string_append (description, ""); + + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: secondary battery */ + status = g_string_new(C_("Battery power", "Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 10 && show_caution) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Caution")); + } + else if (percentage < 30) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Low")); + } + else + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Good")); + } + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Empty")); + break; + default: + status = g_string_new (up_device_state_to_string (state)); + break; + } + g_string_prepend (status, ""); + g_string_append (status, ""); + + /* create the new widget */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_widget_set_hexpand (hbox, TRUE); + widget = gtk_image_new (); + gtk_misc_set_alignment (GTK_MISC (widget), 0.5f, 0.0f); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_DND); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), description->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), status->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_level_bar_new (); + gtk_widget_set_margin_right (widget, 32); + gtk_widget_set_margin_top (widget, 3); + gtk_level_bar_set_value (GTK_LEVEL_BAR (widget), percentage / 100.0f); + gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + /* add to the grid */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + + /* two devices wide */ + gtk_grid_attach (GTK_GRID (widget), hbox, + *secondary_devices_cnt % 2, + (*secondary_devices_cnt / 2) - 1, + 1, 1); + (*secondary_devices_cnt)++; + + /* show panel */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_show_all (widget); + + g_string_free (description, TRUE); + g_string_free (status, TRUE); +} + +static void +get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + CcPowerPanel *panel; + CcPowerPanelPrivate *priv; + gboolean got_primary = FALSE; + gboolean ups_as_primary_device = FALSE; + GError *error = NULL; + gsize n_devices; + GList *children; + GList *l; + GtkWidget *widget; + guint i; + guint secondary_devices_cnt = 0; + GVariant *child; + GVariant *result; + GVariant *untuple; + UpDeviceKind kind; + UpDeviceState state; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; /* Must exit before accessing freed memory */ + } + + panel = CC_POWER_PANEL (user_data); + priv = panel->priv; + + /* empty the secondary box */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (widget), l->data); + g_list_free (children); + + /* hide both panels initially */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_hide (widget); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_hide (widget); + + if (result == NULL) + { + g_printerr ("Error getting devices: %s\n", error->message); + g_error_free (error); + return; + } + + untuple = g_variant_get_child_value (result, 0); + n_devices = g_variant_n_children (untuple); + + /* first we look for a discharging UPS, which is promoted to the + * primary device if it's discharging. Otherwise we use the first + * listed laptop battery as the primary device */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + &state, + NULL); + if (kind == UP_DEVICE_KIND_UPS && + state == UP_DEVICE_STATE_DISCHARGING) + { + ups_as_primary_device = TRUE; + } + g_variant_unref (child); + } + + /* add the devices now we know the state-of-play */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + NULL, + NULL); + if (kind == UP_DEVICE_KIND_LINE_POWER) + { + /* do nothing */ + } + else if (kind == UP_DEVICE_KIND_UPS && ups_as_primary_device) + { + set_device_ups_primary (panel, child); + } + else if (kind == UP_DEVICE_KIND_BATTERY && !ups_as_primary_device) + { + if (!got_primary) + { + set_device_battery_primary (panel, child); + got_primary = TRUE; + } + else + { + set_device_battery_additional (panel, child); + } + } + else + { + add_device_secondary (panel, child, &secondary_devices_cnt); + } + g_variant_unref (child); + } + + g_variant_unref (untuple); + g_variant_unref (result); +} + +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (user_data)->priv; + + /* get the new state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GDBusProxy *proxy; + CcPowerPanelPrivate *priv; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* Access user_data after checking for error because user_data might be + disposed already. */ + priv = CC_POWER_PANEL (user_data)->priv; + priv->proxy = proxy; + + /* we want to change the primary device changes */ + g_signal_connect (priv->proxy, + "g-properties-changed", + G_CALLBACK (on_properties_changed), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly expand the dialog */ + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +combo_time_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both keys */ + g_settings_set_int (self->priv->gsd_settings, key, value); +} + +static void +combo_enum_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_enum (self->priv->gsd_settings, key, value); +} + +static void +disable_unavailable_combo_items (CcPowerPanel *self, + GtkComboBox *combo_box) +{ + gboolean enabled; + gboolean ret; + gint value_tmp; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkTreeModel *model; + + /* setup the renderer */ + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", ACTION_MODEL_TEXT, + "sensitive", ACTION_MODEL_SENSITIVE, + NULL); + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* disable any actions we cannot do */ + do + { + gtk_tree_model_get (model, &iter, + ACTION_MODEL_VALUE, &value_tmp, + -1); + switch (value_tmp) { + case GSD_POWER_ACTION_SUSPEND: + enabled = up_client_get_can_suspend (self->priv->up_client); + break; + case GSD_POWER_ACTION_HIBERNATE: + enabled = up_client_get_can_hibernate (self->priv->up_client); + break; + default: + enabled = TRUE; + } + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + ACTION_MODEL_SENSITIVE, enabled, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_value_for_combo (GtkComboBox *combo_box, gint value) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value_tmp; + gboolean ret; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* try to make the UI match the setting */ + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_ac_battery_ui_mode (CcPowerPanel *self) +{ + gboolean has_batteries = FALSE; + gboolean has_lid = FALSE; + gboolean ret; + GError *error = NULL; + GPtrArray *devices; + guint i; + UpDevice *device; + UpDeviceKind kind; + CcPowerPanelPrivate *priv = self->priv; + + /* this is sync, but it's cached in the daemon and so quick */ + ret = up_client_enumerate_devices_sync (self->priv->up_client, NULL, &error); + if (!ret) + { + g_warning ("failed to get device list: %s", error->message); + g_error_free (error); + goto out; + } + + devices = up_client_get_devices (self->priv->up_client); + for (i=0; ilen; i++) + { + device = g_ptr_array_index (devices, i); + g_object_get (device, + "kind", &kind, + NULL); + if (kind == UP_DEVICE_KIND_BATTERY || + kind == UP_DEVICE_KIND_UPS) + { + has_batteries = TRUE; + break; + } + } + g_ptr_array_unref (devices); + + has_lid = up_client_get_lid_is_present (self->priv->up_client); + +out: + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_ac"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_lid_action"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_battery"), has_batteries && has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_critical"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_critical"), has_batteries); +} + +static gboolean +activate_link_cb (GtkLabel *label, gchar *uri, CcPowerPanel *self) +{ + CcShell *shell; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, uri, NULL, &error) == FALSE) + { + g_warning ("Failed to activate %s panel: %s", uri, error->message); + g_error_free (error); + } + return TRUE; +} + +static void +cc_power_panel_init (CcPowerPanel *self) +{ + GError *error; + GtkWidget *widget; + gint value; + char *text; + + self->priv = POWER_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/power.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + /* add levelbar */ + self->priv->levelbar_primary = GTK_WIDGET + (gtk_builder_get_object (self->priv->builder, "levelbar_primary")); + self->priv->cancellable = g_cancellable_new (); + + /* get initial icon state */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power", + self->priv->cancellable, + got_power_proxy_cb, + self); + + /* find out if there are any battery or UPS devices attached + * and setup UI accordingly */ + self->priv->up_client = up_client_new (); + set_ac_battery_ui_mode (self); + + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + g_signal_connect (self->priv->gsd_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + + /* auto-sleep time */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-ac-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_ac")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-ac-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-battery-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_battery")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-battery-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + + /* actions */ + value = g_settings_get_enum (self->priv->gsd_settings, "critical-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_critical")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "critical-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + /* set screen link */ + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "label_screen_settings")); + /* TRANSLATORS: this is a link to the "Brightness and Lock" control center panel */ + text = g_strdup_printf ("%s", + _("Tip: screen brightness affects how much power is used")); + gtk_label_set_markup (GTK_LABEL (widget), text); + g_free (text); + + g_signal_connect (widget, "activate-link", + G_CALLBACK (activate_link_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-ac-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_ac")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-ac-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_battery")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + widget = WID (self->priv->builder, "vbox_power"); + gtk_widget_reparent (widget, (GtkWidget *) self); +} + +void +cc_power_panel_register (GIOModule *module) +{ + cc_power_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_POWER_PANEL, + "power", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/printers/cc-printers-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/printers/cc-printers-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/printers/cc-printers-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/printers/cc-printers-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,3012 @@ +/* + * Copyright (C) 2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "cc-printers-panel.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#include "cc-editable-entry.h" +#include "pp-new-printer-dialog.h" +#include "pp-ppd-selection-dialog.h" +#include "pp-options-dialog.h" +#include "pp-jobs-dialog.h" +#include "pp-utils.h" +#include "pp-maintenance-command.h" + +CC_PANEL_REGISTER (CcPrintersPanel, cc_printers_panel) + +#define PRINTERS_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_PRINTERS_PANEL, CcPrintersPanelPrivate)) + +#define SUPPLY_BAR_HEIGHT 20 + +#define EMPTY_TEXT "\xe2\x80\x94" + +#define RENEW_INTERVAL 500 +#define SUBSCRIPTION_DURATION 600 + +#define CUPS_DBUS_NAME "org.cups.cupsd.Notifier" +#define CUPS_DBUS_PATH "/org/cups/cupsd/Notifier" +#define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier" + +#define CUPS_STATUS_CHECK_INTERVAL 5 + +#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5) +#define HAVE_CUPS_1_6 1 +#endif + +#ifndef HAVE_CUPS_1_6 +#define ippGetState(ipp) ipp->state +#define ippGetStatusCode(ipp) ipp->request.status.status_code +#define ippGetString(attr, element, language) attr->values[element].string.text +#endif + +struct _CcPrintersPanelPrivate +{ + GtkBuilder *builder; + + cups_dest_t *dests; + gchar **dest_model_names; + gchar **ppd_file_names; + int num_dests; + int current_dest; + + int num_jobs; + + GdkRGBA background_color; + + GPermission *permission; + + GSettings *lockdown_settings; + + PpNewPrinterDialog *pp_new_printer_dialog; + PpPPDSelectionDialog *pp_ppd_selection_dialog; + PpOptionsDialog *pp_options_dialog; + PpJobsDialog *pp_jobs_dialog; + + GDBusProxy *cups_proxy; + GDBusConnection *cups_bus_connection; + gint subscription_id; + guint subscription_renewal_id; + guint cups_status_check_id; + guint dbus_subscription_id; + + GtkWidget *popup_menu; + GList *driver_change_list; + GCancellable *get_ppd_name_cancellable; + gboolean getting_ppd_names; + PPDList *all_ppds_list; + GHashTable *preferred_drivers; + GCancellable *get_all_ppds_cancellable; + + gchar *new_printer_name; + gchar *new_printer_location; + gchar *new_printer_make_and_model; + gboolean new_printer_on_network; + gboolean select_new_printer; + + gpointer dummy; +}; + +typedef struct +{ + gchar *printer_name; + GCancellable *cancellable; +} SetPPDItem; + +static void update_jobs_count (CcPrintersPanel *self); +static void actualize_printers_list (CcPrintersPanel *self); +static void update_sensitivity (gpointer user_data); +static void printer_disable_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data); +static void printer_set_default_cb (GtkToggleButton *button, gpointer user_data); +static void detach_from_cups_notifier (gpointer data); +static void free_dests (CcPrintersPanel *self); + +static void +cc_printers_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_printers_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_printers_panel_dispose (GObject *object) +{ + CcPrintersPanelPrivate *priv = CC_PRINTERS_PANEL (object)->priv; + + if (priv->pp_new_printer_dialog) + g_clear_object (&priv->pp_new_printer_dialog); + + free_dests (CC_PRINTERS_PANEL (object)); + + g_clear_pointer (&priv->new_printer_name, g_free); + g_clear_pointer (&priv->new_printer_location, g_free); + g_clear_pointer (&priv->new_printer_make_and_model, g_free); + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + + if (priv->permission) + { + g_object_unref (priv->permission); + priv->permission = NULL; + } + + detach_from_cups_notifier (CC_PRINTERS_PANEL (object)); + + if (priv->cups_status_check_id > 0) + { + g_source_remove (priv->cups_status_check_id); + priv->cups_status_check_id = 0; + } + + if (priv->all_ppds_list) + { + ppd_list_free (priv->all_ppds_list); + priv->all_ppds_list = NULL; + } + + if (priv->preferred_drivers) + { + g_hash_table_unref (priv->preferred_drivers); + priv->preferred_drivers = NULL; + } + + if (priv->get_all_ppds_cancellable) + { + g_cancellable_cancel (priv->get_all_ppds_cancellable); + g_object_unref (priv->get_all_ppds_cancellable); + priv->get_all_ppds_cancellable = NULL; + } + + if (priv->driver_change_list) + { + GList *iter; + + for (iter = priv->driver_change_list; iter; iter = iter->next) + { + SetPPDItem *item = (SetPPDItem *) iter->data; + + g_cancellable_cancel (item->cancellable); + g_object_unref (item->cancellable); + g_free (item->printer_name); + g_free (item); + } + + g_list_free (priv->driver_change_list); + priv->driver_change_list = NULL; + } + + G_OBJECT_CLASS (cc_printers_panel_parent_class)->dispose (object); +} + +static void +cc_printers_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_printers_panel_parent_class)->finalize (object); +} + +static GPermission * +cc_printers_panel_get_permission (CcPanel *panel) +{ + CcPrintersPanelPrivate *priv = CC_PRINTERS_PANEL (panel)->priv; + + return priv->permission; +} + +static const char * +cc_printers_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/printing"; +} + +static void +cc_printers_panel_class_init (CcPrintersPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcPrintersPanelPrivate)); + + object_class->get_property = cc_printers_panel_get_property; + object_class->set_property = cc_printers_panel_set_property; + object_class->dispose = cc_printers_panel_dispose; + object_class->finalize = cc_printers_panel_finalize; + + panel_class->get_permission = cc_printers_panel_get_permission; + panel_class->get_help_uri = cc_printers_panel_get_help_uri; +} + +static void +on_cups_notification (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + CcPrintersPanelPrivate *priv; + gboolean printer_is_accepting_jobs; + gchar *printer_name = NULL; + gchar *text = NULL; + gchar *printer_uri = NULL; + gchar *printer_state_reasons = NULL; + gchar *job_state_reasons = NULL; + gchar *job_name = NULL; + guint job_id; + gint printer_state; + gint job_state; + gint job_impressions_completed; + static const char * const requested_attrs[] = { + "job-printer-uri", + "job-originating-user-name"}; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (g_strcmp0 (signal_name, "PrinterAdded") != 0 && + g_strcmp0 (signal_name, "PrinterDeleted") != 0 && + g_strcmp0 (signal_name, "PrinterStateChanged") != 0 && + g_strcmp0 (signal_name, "PrinterStopped") != 0 && + g_strcmp0 (signal_name, "JobCreated") != 0 && + g_strcmp0 (signal_name, "JobCompleted") != 0) + return; + + if (g_variant_n_children (parameters) == 1) + g_variant_get (parameters, "(&s)", &text); + else if (g_variant_n_children (parameters) == 6) + { + g_variant_get (parameters, "(&s&s&su&sb)", + &text, + &printer_uri, + &printer_name, + &printer_state, + &printer_state_reasons, + &printer_is_accepting_jobs); + } + else if (g_variant_n_children (parameters) == 11) + { + g_variant_get (parameters, "(&s&s&su&sbuu&s&su)", + &text, + &printer_uri, + &printer_name, + &printer_state, + &printer_state_reasons, + &printer_is_accepting_jobs, + &job_id, + &job_state, + &job_state_reasons, + &job_name, + &job_impressions_completed); + } + + if (g_strcmp0 (signal_name, "PrinterAdded") == 0 || + g_strcmp0 (signal_name, "PrinterDeleted") == 0 || + g_strcmp0 (signal_name, "PrinterStateChanged") == 0 || + g_strcmp0 (signal_name, "PrinterStopped") == 0) + actualize_printers_list (self); + else if (g_strcmp0 (signal_name, "JobCreated") == 0 || + g_strcmp0 (signal_name, "JobCompleted") == 0) + { + http_t *http; + gchar *job_uri; + ipp_t *request, *response; + + job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", job_id); + if ((http = httpConnectEncrypt (cupsServer (), ippPort (), + cupsEncryption ())) != NULL) + { + request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "job-uri", NULL, job_uri); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser ()); + ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", G_N_ELEMENTS (requested_attrs), NULL, requested_attrs); + response = cupsDoRequest (http, request, "/"); + + if (response) + { + if (ippGetStatusCode (response) <= IPP_OK_CONFLICT) + { + ipp_attribute_t *attr_username = NULL; + ipp_attribute_t *attr_printer_uri = NULL; + + attr_username = ippFindAttribute(response, "job-originating-user-name", IPP_TAG_NAME); + attr_printer_uri = ippFindAttribute(response, "job-printer-uri", IPP_TAG_URI); + if (attr_username && attr_printer_uri && + g_strcmp0 (ippGetString (attr_username, 0, NULL), cupsUser ()) == 0 && + g_strrstr (ippGetString (attr_printer_uri, 0, NULL), "/") != 0 && + priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL && + g_strcmp0 (g_strrstr (ippGetString (attr_printer_uri, 0, NULL), "/") + 1, + priv->dests[priv->current_dest].name) == 0) + update_jobs_count (self); + } + ippDelete(response); + } + httpClose (http); + } + g_free (job_uri); + } +} + +static gboolean +renew_subscription (gpointer data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) data; + static const char * const events[] = { + "printer-added", + "printer-deleted", + "printer-stopped", + "printer-state-changed", + "job-created", + "job-completed"}; + + priv = PRINTERS_PANEL_PRIVATE (self); + + priv->subscription_id = renew_cups_subscription (priv->subscription_id, + events, + G_N_ELEMENTS (events), + SUBSCRIPTION_DURATION); + + if (priv->subscription_id > 0) + return TRUE; + else + return FALSE; +} + +static void +attach_to_cups_notifier (gpointer data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) data; + GError *error = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (renew_subscription (self)) + { + priv->subscription_renewal_id = + g_timeout_add_seconds (RENEW_INTERVAL, renew_subscription, self); + + priv->cups_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + 0, + NULL, + CUPS_DBUS_NAME, + CUPS_DBUS_PATH, + CUPS_DBUS_INTERFACE, + NULL, + &error); + + if (!priv->cups_proxy) + { + g_warning ("%s", error->message); + g_error_free (error); + return; + } + + priv->cups_bus_connection = g_dbus_proxy_get_connection (priv->cups_proxy); + + priv->dbus_subscription_id = + g_dbus_connection_signal_subscribe (priv->cups_bus_connection, + NULL, + CUPS_DBUS_INTERFACE, + NULL, + CUPS_DBUS_PATH, + NULL, + 0, + on_cups_notification, + self, + NULL); + } +} + +static void +detach_from_cups_notifier (gpointer data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->dbus_subscription_id != 0) { + g_dbus_connection_signal_unsubscribe (priv->cups_bus_connection, + priv->dbus_subscription_id); + priv->dbus_subscription_id = 0; + } + + cancel_cups_subscription (priv->subscription_id); + priv->subscription_id = 0; + + if (priv->subscription_renewal_id != 0) { + g_source_remove (priv->subscription_renewal_id); + priv->subscription_renewal_id = 0; + } + + if (priv->cups_proxy != NULL) { + g_object_unref (priv->cups_proxy); + priv->cups_proxy = NULL; + } +} + +static void +free_dests (CcPrintersPanel *self) +{ + CcPrintersPanelPrivate *priv; + gint i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->num_dests > 0) + { + for (i = 0; i < priv->num_dests; i++) + { + g_free (priv->dest_model_names[i]); + if (priv->ppd_file_names[i]) { + g_unlink (priv->ppd_file_names[i]); + g_free (priv->ppd_file_names[i]); + } + } + g_free (priv->dest_model_names); + g_free (priv->ppd_file_names); + cupsFreeDests (priv->num_dests, priv->dests); + } + priv->dests = NULL; + priv->num_dests = 0; + priv->current_dest = -1; + priv->dest_model_names = NULL; + priv->ppd_file_names = NULL; +} + +enum +{ + NOTEBOOK_INFO_PAGE = 0, + NOTEBOOK_NO_PRINTERS_PAGE, + NOTEBOOK_NO_CUPS_PAGE, + NOTEBOOK_N_PAGES +}; + +enum +{ + PRINTER_ID_COLUMN, + PRINTER_NAME_COLUMN, + PRINTER_PAUSED_COLUMN, + PRINTER_DEFAULT_ICON_COLUMN, + PRINTER_ICON_COLUMN, + PRINTER_N_COLUMNS +}; + +static void +printer_selection_changed_cb (GtkTreeSelection *selection, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkTreeModel *model; + cups_ptype_t type = 0; + GtkTreeIter iter; + GtkWidget *widget; + GtkWidget *model_button; + GtkWidget *model_label; + GValue value = G_VALUE_INIT; + gchar *printer_make_and_model = NULL; + gchar *printer_model = NULL; + gchar *reason = NULL; + gchar **printer_reasons = NULL; + gchar *marker_types = NULL; + gchar *printer_name = NULL; + gchar *printer_icon = NULL; + gchar *printer_type = NULL; + gchar *supply_type = NULL; + gchar *printer_uri = NULL; + gchar *location = NULL; + gchar *status = NULL; + gchar *device_uri = NULL; + gchar *printer_hostname = NULL; + int printer_state = 3; + int id = -1; + int i, j; + static const char * const reasons[] = + { + "toner-low", + "toner-empty", + "developer-low", + "developer-empty", + "marker-supply-low", + "marker-supply-empty", + "cover-open", + "door-open", + "media-low", + "media-empty", + "offline", + "paused", + "marker-waste-almost-full", + "marker-waste-full", + "opc-near-eol", + "opc-life-over" + }; + static const char * statuses[] = + { + /* Translators: The printer is low on toner */ + N_("Low on toner"), + /* Translators: The printer has no toner left */ + N_("Out of toner"), + /* Translators: "Developer" is a chemical for photo development, + * http://en.wikipedia.org/wiki/Photographic_developer */ + N_("Low on developer"), + /* Translators: "Developer" is a chemical for photo development, + * http://en.wikipedia.org/wiki/Photographic_developer */ + N_("Out of developer"), + /* Translators: "marker" is one color bin of the printer */ + N_("Low on a marker supply"), + /* Translators: "marker" is one color bin of the printer */ + N_("Out of a marker supply"), + /* Translators: One or more covers on the printer are open */ + N_("Open cover"), + /* Translators: One or more doors on the printer are open */ + N_("Open door"), + /* Translators: At least one input tray is low on media */ + N_("Low on paper"), + /* Translators: At least one input tray is empty */ + N_("Out of paper"), + /* Translators: The printer is offline */ + NC_("printer state", "Offline"), + /* Translators: Someone has paused the Printer */ + NC_("printer state", "Paused"), + /* Translators: The printer marker supply waste receptacle is almost full */ + N_("Waste receptacle almost full"), + /* Translators: The printer marker supply waste receptacle is full */ + N_("Waste receptacle full"), + /* Translators: Optical photo conductors are used in laser printers */ + N_("The optical photo conductor is near end of life"), + /* Translators: Optical photo conductors are used in laser printers */ + N_("The optical photo conductor is no longer functioning") + }; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + PRINTER_ID_COLUMN, &id, + PRINTER_NAME_COLUMN, &printer_name, + PRINTER_ICON_COLUMN, &printer_icon, + -1); + } + else + id = -1; + + priv->current_dest = id; + + update_jobs_count (self); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "notebook"); + if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) >= NOTEBOOK_NO_PRINTERS_PAGE) + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_INFO_PAGE); + + for (i = 0; i < priv->dests[id].num_options; i++) + { + if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-location") == 0) + location = g_strdup (priv->dests[priv->current_dest].options[i].value); + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state") == 0) + printer_state = atoi (priv->dests[priv->current_dest].options[i].value); + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state-reasons") == 0) + reason = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-types") == 0) + marker_types = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-make-and-model") == 0) + printer_make_and_model = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-uri-supported") == 0) + printer_uri = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-type") == 0) + printer_type = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "device-uri") == 0) + device_uri = priv->dests[priv->current_dest].options[i].value; + } + + if (priv->ppd_file_names[priv->current_dest] == NULL) + priv->ppd_file_names[priv->current_dest] = + g_strdup (cupsGetPPD (priv->dests[priv->current_dest].name)); + + if (priv->dest_model_names[priv->current_dest] == NULL) + priv->dest_model_names[priv->current_dest] = + get_ppd_attribute (priv->ppd_file_names[priv->current_dest], + "ModelName"); + + printer_model = g_strdup (priv->dest_model_names[priv->current_dest]); + + if (printer_model == NULL && printer_make_and_model) + { + gchar *breakpoint = NULL, *tmp = NULL, *tmp2 = NULL; + gchar backup; + size_t length = 0; + gchar *forbiden[] = { + "foomatic", + ",", + "hpijs", + "hpcups", + "(recommended)", + "postscript (recommended)", + NULL }; + + tmp = g_ascii_strdown (printer_make_and_model, -1); + + for (i = 0; i < g_strv_length (forbiden); i++) + { + tmp2 = g_strrstr (tmp, forbiden[i]); + if (breakpoint == NULL || + (tmp2 != NULL && tmp2 < breakpoint)) + breakpoint = tmp2; + } + + if (breakpoint) + { + backup = *breakpoint; + *breakpoint = '\0'; + length = strlen (tmp); + *breakpoint = backup; + g_free (tmp); + + if (length > 0) + printer_model = g_strndup (printer_make_and_model, length); + } + else + printer_model = g_strdup (printer_make_and_model); + } + + if (priv->new_printer_name && + g_strcmp0 (priv->new_printer_name, printer_name) == 0) + { + /* Translators: Printer's state (printer is being configured right now) */ + status = g_strdup ( C_("printer state", "Configuring")); + } + + /* Find the first of the most severe reasons + * and show it in the status field + */ + if (!status && + reason && + !g_str_equal (reason, "none")) + { + int errors = 0, warnings = 0, reports = 0; + int error_index = -1, warning_index = -1, report_index = -1; + + printer_reasons = g_strsplit (reason, ",", -1); + for (i = 0; i < g_strv_length (printer_reasons); i++) + { + for (j = 0; j < G_N_ELEMENTS (reasons); j++) + if (strncmp (printer_reasons[i], + reasons[j], + strlen (reasons[j])) == 0) + { + if (g_str_has_suffix (printer_reasons[i], "-report")) + { + if (reports == 0) + report_index = j; + reports++; + } + else if (g_str_has_suffix (printer_reasons[i], "-warning")) + { + if (warnings == 0) + warning_index = j; + warnings++; + } + else + { + if (errors == 0) + error_index = j; + errors++; + } + } + } + g_strfreev (printer_reasons); + + if (error_index >= 0) + status = g_strdup (_(statuses[error_index])); + else if (warning_index >= 0) + status = g_strdup (_(statuses[warning_index])); + else if (report_index >= 0) + status = g_strdup (_(statuses[report_index])); + } + + if (status == NULL) + { + switch (printer_state) + { + case 3: + /* Translators: Printer's state (can start new job without waiting) */ + status = g_strdup ( C_("printer state", "Ready")); + break; + case 4: + /* Translators: Printer's state (jobs are processing) */ + status = g_strdup ( C_("printer state", "Processing")); + break; + case 5: + /* Translators: Printer's state (no jobs can be processed) */ + status = g_strdup ( C_("printer state", "Stopped")); + break; + } + } + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-icon"); + g_value_init (&value, G_TYPE_INT); + g_object_get_property ((GObject *) widget, "icon-size", &value); + + if (printer_icon) + { + gtk_image_set_from_icon_name ((GtkImage *) widget, printer_icon, g_value_get_int (&value)); + g_free (printer_icon); + } + else + gtk_image_set_from_icon_name ((GtkImage *) widget, "printer", g_value_get_int (&value)); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-name-label"); + + if (printer_name) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_name); + g_free (printer_name); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-status-label"); + + if (status) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), status); + g_free (status); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-location-label"); + + if (location) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), location); + g_free (location); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + + model_button = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-button"); + + model_label = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-label"); + + if (printer_model) + { + gtk_button_set_label (GTK_BUTTON (model_button), printer_model); + gtk_label_set_text (GTK_LABEL (model_label), printer_model); + g_free (printer_model); + } + else + { + gtk_button_set_label (GTK_BUTTON (model_button), EMPTY_TEXT); + gtk_label_set_text (GTK_LABEL (model_label), EMPTY_TEXT); + } + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-ip-address-label"); + + if (printer_type) + type = atoi (printer_type); + + printer_hostname = printer_get_hostname (type, device_uri, printer_uri); + + if (printer_hostname) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_hostname); + g_free (printer_hostname); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-disable-switch"); + + g_signal_handlers_block_by_func (G_OBJECT (widget), printer_disable_cb, self); + gtk_switch_set_active (GTK_SWITCH (widget), printer_state != 5); + g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_disable_cb, self); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-default-check-button"); + + g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->dests[id].is_default); + g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "supply-drawing-area"); + gtk_widget_set_size_request (widget, -1, SUPPLY_BAR_HEIGHT); + gtk_widget_queue_draw (widget); + + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "supply-label"); + + if (marker_types && g_strrstr (marker_types, "toner") != NULL) + /* Translators: Toner supply */ + supply_type = g_strdup ( _("Toner Level")); + else if (marker_types && g_strrstr (marker_types, "ink") != NULL) + /* Translators: Ink supply */ + supply_type = g_strdup ( _("Ink Level")); + else + /* Translators: By supply we mean ink, toner, staples, water, ... */ + supply_type = g_strdup ( _("Supply Level")); + + if (supply_type) + { + gtk_label_set_text (GTK_LABEL (widget), supply_type); + g_free (supply_type); + } + else + gtk_label_set_text (GTK_LABEL (widget), EMPTY_TEXT); + } + else + { + if (id == -1) + { + if (priv->new_printer_name && + g_strcmp0 (priv->new_printer_name, printer_name) == 0) + { + /* Translators: Printer's state (printer is being installed right now) */ + status = g_strdup ( C_("printer state", "Installing")); + location = g_strdup (priv->new_printer_location); + printer_model = g_strdup (priv->new_printer_make_and_model); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "notebook"); + if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) >= NOTEBOOK_NO_PRINTERS_PAGE) + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_INFO_PAGE); + } + } + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-icon"); + g_value_init (&value, G_TYPE_INT); + g_object_get_property ((GObject *) widget, "icon-size", &value); + + if (printer_icon) + { + gtk_image_set_from_icon_name ((GtkImage *) widget, printer_icon, g_value_get_int (&value)); + g_free (printer_icon); + } + else + gtk_image_set_from_icon_name ((GtkImage *) widget, "printer", g_value_get_int (&value)); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-name-label"); + if (printer_name) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_name); + g_free (printer_name); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-status-label"); + if (status) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), status); + g_free (status); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-location-label"); + + if (location) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), location); + g_free (location); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + + model_button = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-button"); + + model_label = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-label"); + + if (printer_model) + { + gtk_button_set_label (GTK_BUTTON (model_button), printer_model); + gtk_label_set_text (GTK_LABEL (model_label), printer_model); + g_free (printer_model); + } + else + { + gtk_button_set_label (GTK_BUTTON (model_button), EMPTY_TEXT); + gtk_label_set_text (GTK_LABEL (model_label), EMPTY_TEXT); + } + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-ip-address-label"); + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-jobs-label"); + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-disable-switch"); + + g_signal_handlers_block_by_func (G_OBJECT (widget), printer_disable_cb, self); + gtk_switch_set_active (GTK_SWITCH (widget), FALSE); + g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_disable_cb, self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-default-check-button"); + + g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE); + g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self); + } + + update_sensitivity (self); +} + +static void +actualize_printers_list (CcPrintersPanel *self) +{ + CcPrintersPanelPrivate *priv; + GtkTreeSelection *selection; + GtkListStore *store; + cups_ptype_t printer_type = 0; + GtkTreeModel *model; + GtkTreeIter selected_iter; + GtkTreeView *treeview; + GtkTreeIter iter; + cups_job_t *jobs = NULL; + GtkWidget *widget; + gboolean paused = FALSE; + gboolean selected_iter_set = FALSE; + gboolean valid = FALSE; + http_t *http; + gchar *current_printer_name = NULL; + gchar *printer_icon_name = NULL; + gchar *default_icon_name = NULL; + gchar *device_uri = NULL; + gint new_printer_position = 0; + int current_dest = -1; + int i, j; + int num_jobs = 0; + + priv = PRINTERS_PANEL_PRIVATE (self); + + treeview = (GtkTreeView*) + gtk_builder_get_object (priv->builder, "printers-treeview"); + + if ((selection = gtk_tree_view_get_selection (treeview)) != NULL && + gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + PRINTER_NAME_COLUMN, ¤t_printer_name, + -1); + } + + if (priv->new_printer_name && + priv->select_new_printer) + { + g_free (current_printer_name); + current_printer_name = g_strdup (priv->new_printer_name); + priv->select_new_printer = FALSE; + } + + free_dests (self); + priv->num_dests = cupsGetDests (&priv->dests); + priv->dest_model_names = g_new0 (gchar *, priv->num_dests); + priv->ppd_file_names = g_new0 (gchar *, priv->num_dests); + + store = gtk_list_store_new (PRINTER_N_COLUMNS, + G_TYPE_INT, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_STRING, + G_TYPE_STRING); + + if (priv->num_dests == 0 && !priv->new_printer_name) + { + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "notebook"); + + http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ()); + if (http) + { + httpClose (http); + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_NO_PRINTERS_PAGE); + } + else + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_NO_CUPS_PAGE); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + PRINTER_ID_COLUMN, 0, + /* Translators: There are no printers available (none is configured or CUPS is not running) */ + PRINTER_NAME_COLUMN, _("No printers available"), + PRINTER_PAUSED_COLUMN, TRUE, + PRINTER_DEFAULT_ICON_COLUMN, NULL, + PRINTER_ICON_COLUMN, NULL, + -1); + gtk_widget_set_sensitive (GTK_WIDGET (treeview), FALSE); + } + else + gtk_widget_set_sensitive (GTK_WIDGET (treeview), TRUE); + + for (i = 0; i < priv->num_dests; i++) + { + gchar *instance; + + if (priv->new_printer_name && new_printer_position >= 0) + { + gint comparison_result = g_ascii_strcasecmp (priv->dests[i].name, priv->new_printer_name); + + if (comparison_result < 0) + new_printer_position = i + 1; + else if (comparison_result == 0) + new_printer_position = -1; + } + + gtk_list_store_append (store, &iter); + + if (priv->dests[i].instance) + { + instance = g_strdup_printf ("%s / %s", priv->dests[i].name, priv->dests[i].instance); + } + else + { + instance = g_strdup (priv->dests[i].name); + } + + for (j = 0; j < priv->dests[i].num_options; j++) + { + if (g_strcmp0 (priv->dests[i].options[j].name, "printer-state") == 0) + paused = (g_strcmp0 (priv->dests[i].options[j].value, "5") == 0); + else if (g_strcmp0 (priv->dests[i].options[j].name, "device-uri") == 0) + device_uri = priv->dests[i].options[j].value; + else if (g_strcmp0 (priv->dests[i].options[j].name, "printer-type") == 0) + printer_type = atoi (priv->dests[i].options[j].value); + } + + if (priv->dests[i].is_default) + default_icon_name = g_strdup ("emblem-default-symbolic"); + else + default_icon_name = NULL; + + if (printer_is_local (printer_type, device_uri)) + printer_icon_name = g_strdup ("printer"); + else + printer_icon_name = g_strdup ("printer-network"); + + gtk_list_store_set (store, &iter, + PRINTER_ID_COLUMN, i, + PRINTER_NAME_COLUMN, instance, + PRINTER_PAUSED_COLUMN, paused, + PRINTER_DEFAULT_ICON_COLUMN, default_icon_name, + PRINTER_ICON_COLUMN, printer_icon_name, + -1); + + if (g_strcmp0 (current_printer_name, instance) == 0) + { + current_dest = i; + selected_iter = iter; + selected_iter_set = TRUE; + } + + g_free (instance); + g_free (printer_icon_name); + g_free (default_icon_name); + } + + if (priv->new_printer_name && new_printer_position >= 0) + { + gtk_list_store_insert (store, &iter, new_printer_position); + gtk_list_store_set (store, &iter, + PRINTER_ID_COLUMN, -1, + PRINTER_NAME_COLUMN, priv->new_printer_name, + PRINTER_PAUSED_COLUMN, TRUE, + PRINTER_DEFAULT_ICON_COLUMN, NULL, + PRINTER_ICON_COLUMN, priv->new_printer_on_network ? + "printer-network" : "printer", + -1); + + if (g_strcmp0 (current_printer_name, priv->new_printer_name) == 0) + { + selected_iter = iter; + selected_iter_set = TRUE; + } + } + + g_signal_handlers_block_by_func ( + G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))), + printer_selection_changed_cb, + self); + + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store)); + + g_signal_handlers_unblock_by_func ( + G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))), + printer_selection_changed_cb, + self); + + if (selected_iter_set) + { + priv->current_dest = current_dest; + gtk_tree_selection_select_iter ( + gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + &selected_iter); + } + else + { + num_jobs = cupsGetJobs (&jobs, NULL, 1, CUPS_WHICHJOBS_ALL); + + /* Select last used printer */ + if (num_jobs > 0) + { + for (i = 0; i < priv->num_dests; i++) + if (g_strcmp0 (priv->dests[i].name, jobs[num_jobs - 1].dest) == 0) + { + priv->current_dest = i; + break; + } + cupsFreeJobs (num_jobs, jobs); + } + + /* Select default printer */ + if (priv->current_dest < 0) + { + for (i = 0; i < priv->num_dests; i++) + if (priv->dests[i].is_default) + { + priv->current_dest = i; + break; + } + } + + if (priv->current_dest >= 0) + { + gint id; + valid = gtk_tree_model_get_iter_first ((GtkTreeModel *) store, + &selected_iter); + + while (valid) + { + gtk_tree_model_get ((GtkTreeModel *) store, &selected_iter, + PRINTER_ID_COLUMN, &id, + -1); + if (id == priv->current_dest) + break; + + valid = gtk_tree_model_iter_next ((GtkTreeModel *) store, + &selected_iter); + } + + gtk_tree_selection_select_iter ( + gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + &selected_iter); + } + else if (priv->num_dests > 0) + { + /* Select first printer */ + gtk_tree_model_get_iter_first ((GtkTreeModel *) store, + &selected_iter); + + gtk_tree_selection_select_iter ( + gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + &selected_iter); + } + } + + g_free (current_printer_name); + g_object_unref (store); + + update_sensitivity (self); +} + +static void +set_cell_sensitivity_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer func_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) func_data; + gboolean paused = FALSE; + + priv = PRINTERS_PANEL_PRIVATE (self); + + gtk_tree_model_get (tree_model, iter, PRINTER_PAUSED_COLUMN, &paused, -1); + + if (priv->num_dests == 0) + g_object_set (G_OBJECT (cell), + "ellipsize", PANGO_ELLIPSIZE_NONE, + "width-chars", -1, + NULL); + else + g_object_set (G_OBJECT (cell), + "ellipsize", PANGO_ELLIPSIZE_END, + "width-chars", 18, + NULL); + + g_object_set (cell, "sensitive", !paused, NULL); +} + +static void +set_pixbuf_cell_sensitivity_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer func_data) +{ + gboolean paused = FALSE; + + gtk_tree_model_get (tree_model, iter, PRINTER_PAUSED_COLUMN, &paused, -1); + g_object_set (cell, "sensitive", !paused, NULL); +} + +static void +populate_printers_list (CcPrintersPanel *self) +{ + CcPrintersPanelPrivate *priv; + GtkTreeViewColumn *column; + GtkCellRenderer *icon_renderer; + GtkCellRenderer *icon_renderer2; + GtkCellRenderer *renderer; + GtkWidget *treeview; + + priv = PRINTERS_PANEL_PRIVATE (self); + + treeview = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printers-treeview"); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + "changed", G_CALLBACK (printer_selection_changed_cb), self); + + actualize_printers_list (self); + + + icon_renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (icon_renderer, "stock-size", gtk_icon_size_from_name ("cc-sidebar-list"), NULL); + gtk_cell_renderer_set_padding (icon_renderer, 4, 4); + column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer, + "icon-name", PRINTER_ICON_COLUMN, NULL); + gtk_tree_view_column_set_cell_data_func (column, icon_renderer, set_pixbuf_cell_sensitivity_func, + self, NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, "width-chars", 18, NULL); + column = gtk_tree_view_column_new_with_attributes ("Printer", renderer, + "text", PRINTER_NAME_COLUMN, NULL); + gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, + self, NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_column_set_min_width (column, 120); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + + icon_renderer2 = gtk_cell_renderer_pixbuf_new (); + column = gtk_tree_view_column_new_with_attributes ("Default", icon_renderer2, + "icon-name", PRINTER_DEFAULT_ICON_COLUMN, NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); +} + +enum +{ + JOB_ID_COLUMN, + JOB_TITLE_COLUMN, + JOB_STATE_COLUMN, + JOB_CREATION_TIME_COLUMN, + JOB_N_COLUMNS +}; + +static void +update_jobs_count (CcPrintersPanel *self) +{ + CcPrintersPanelPrivate *priv; + cups_job_t *jobs; + GtkWidget *widget; + gchar *active_jobs = NULL; + gint num_jobs; + + priv = PRINTERS_PANEL_PRIVATE (self); + + priv->num_jobs = -1; + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + priv->num_jobs = cupsGetJobs (&jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE); + if (priv->num_jobs > 0) + cupsFreeJobs (priv->num_jobs, jobs); + + num_jobs = priv->num_jobs < 0 ? 0 : (guint) priv->num_jobs; + /* Translators: there is n active print jobs on this printer */ + active_jobs = g_strdup_printf (ngettext ("%u active", "%u active", num_jobs), num_jobs); + } + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-jobs-label"); + + if (active_jobs) + { + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), active_jobs); + g_free (active_jobs); + } + else + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT); + + if (priv->pp_jobs_dialog) + { + pp_jobs_dialog_update (priv->pp_jobs_dialog); + } +} + +static void +printer_disable_cb (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + gboolean paused = FALSE; + char *name = NULL; + int i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + name = priv->dests[priv->current_dest].name; + + for (i = 0; i < priv->dests[priv->current_dest].num_options; i++) + { + if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-state") == 0) + paused = (g_strcmp0 (priv->dests[priv->current_dest].options[i].value, "5") == 0); + } + } + + if (name && printer_set_enabled (name, paused)) + actualize_printers_list (self); +} + +typedef struct { + gchar *color; + gchar *type; + gchar *name; + gint level; +} MarkerItem; + +static gint +markers_cmp (gconstpointer a, + gconstpointer b) +{ + MarkerItem *x = (MarkerItem*) a; + MarkerItem *y = (MarkerItem*) b; + + if (x->level < y->level) + return 1; + else if (x->level == y->level) + return 0; + else + return -1; +} + +static void +rounded_rectangle (cairo_t *cr, double x, double y, double w, double h, double r) +{ + cairo_new_sub_path (cr); + cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2); + cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI); + cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2); + cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI); + cairo_close_path (cr); +} + +static gboolean +supply_levels_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkStyleContext *context; + gchar *marker_levels = NULL; + gchar *marker_colors = NULL; + gchar *marker_names = NULL; + gchar *marker_types = NULL; + gchar *tooltip_text = NULL; + gint width; + gint height; + int i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + cairo_rectangle (cr, 0.0, 0.0, width, height); + gdk_cairo_set_source_rgba (cr, &priv->background_color); + cairo_fill (cr); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + for (i = 0; i < priv->dests[priv->current_dest].num_options; i++) + { + if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-names") == 0) + marker_names = g_strcompress (priv->dests[priv->current_dest].options[i].value); + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-levels") == 0) + marker_levels = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-colors") == 0) + marker_colors = priv->dests[priv->current_dest].options[i].value; + else if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "marker-types") == 0) + marker_types = priv->dests[priv->current_dest].options[i].value; + } + + if (marker_levels && marker_colors && marker_names && marker_types) + { + GdkRGBA border_color = {0.0, 0.0, 0.0, 1.0}; + GSList *markers = NULL; + GSList *tmp_list = NULL; + GValue int_val = G_VALUE_INIT; + gchar **marker_levelsv = NULL; + gchar **marker_colorsv = NULL; + gchar **marker_namesv = NULL; + gchar **marker_typesv = NULL; + gchar *tmp = NULL; + gint border_radius = 0; + + context = gtk_widget_get_style_context ((GtkWidget *) + gtk_builder_get_object (priv->builder, "printer-options-button")); + gtk_style_context_get_border_color (context, 0, &border_color); + gtk_style_context_get_property ( + context, GTK_STYLE_PROPERTY_BORDER_RADIUS, 0, &int_val); + if (G_VALUE_HOLDS_INT (&int_val)) + border_radius = g_value_get_int (&int_val); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "supply-drawing-area"); + + marker_levelsv = g_strsplit (marker_levels, ",", -1); + marker_colorsv = g_strsplit (marker_colors, ",", -1); + marker_namesv = g_strsplit (marker_names, ",", -1); + marker_typesv = g_strsplit (marker_types, ",", -1); + + if (g_strv_length (marker_levelsv) == g_strv_length (marker_colorsv) && + g_strv_length (marker_colorsv) == g_strv_length (marker_namesv) && + g_strv_length (marker_namesv) == g_strv_length (marker_typesv)) + { + for (i = 0; i < g_strv_length (marker_levelsv); i++) + { + MarkerItem *marker; + + if (g_strcmp0 (marker_typesv[i], "ink") == 0 || + g_strcmp0 (marker_typesv[i], "toner") == 0) + { + marker = g_new0 (MarkerItem, 1); + marker->type = g_strdup (marker_typesv[i]); + marker->name = g_strdup (marker_namesv[i]); + marker->color = g_strdup (marker_colorsv[i]); + marker->level = atoi (marker_levelsv[i]); + + markers = g_slist_prepend (markers, marker); + } + } + + markers = g_slist_sort (markers, markers_cmp); + + for (tmp_list = markers; tmp_list; tmp_list = tmp_list->next) + { + GdkRGBA color = {0.0, 0.0, 0.0, 1.0}; + double display_value; + int value; + + value = ((MarkerItem*) tmp_list->data)->level; + + gdk_rgba_parse (&color, ((MarkerItem*) tmp_list->data)->color); + + if (value > 0) + { + display_value = value / 100.0 * (width - 3.0); + gdk_cairo_set_source_rgba (cr, &color); + rounded_rectangle (cr, 1.5, 1.5, display_value, SUPPLY_BAR_HEIGHT - 3.0, border_radius); + cairo_fill (cr); + } + + if (tooltip_text) + { + tmp = g_strdup_printf ("%s\n%s", + tooltip_text, + ((MarkerItem*) tmp_list->data)->name); + g_free (tooltip_text); + tooltip_text = tmp; + tmp = NULL; + } + else + tooltip_text = g_strdup_printf ("%s", + ((MarkerItem*) tmp_list->data)->name); + } + + cairo_set_line_width (cr, 1.0); + gdk_cairo_set_source_rgba (cr, &border_color); + rounded_rectangle (cr, 1.5, 1.5, width - 3.0, SUPPLY_BAR_HEIGHT - 3.0, border_radius); + cairo_stroke (cr); + + for (tmp_list = markers; tmp_list; tmp_list = tmp_list->next) + { + g_free (((MarkerItem*) tmp_list->data)->name); + g_free (((MarkerItem*) tmp_list->data)->type); + g_free (((MarkerItem*) tmp_list->data)->color); + } + g_slist_free_full (markers, g_free); + } + + g_strfreev (marker_levelsv); + g_strfreev (marker_colorsv); + g_strfreev (marker_namesv); + g_strfreev (marker_typesv); + } + + g_free (marker_names); + + if (tooltip_text) + { + gtk_widget_set_tooltip_text (widget, tooltip_text); + g_free (tooltip_text); + } + else + { + gtk_widget_set_tooltip_text (widget, NULL); + gtk_widget_set_has_tooltip (widget, FALSE); + } + } + + return TRUE; +} + +static void +printer_set_default_cb (GtkToggleButton *button, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + char *name = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + name = priv->dests[priv->current_dest].name; + + if (name) + { + printer_set_default (name); + actualize_printers_list (self); + + g_signal_handlers_block_by_func (G_OBJECT (button), printer_set_default_cb, self); + gtk_toggle_button_set_active (button, priv->dests[priv->current_dest].is_default); + g_signal_handlers_unblock_by_func (G_OBJECT (button), printer_set_default_cb, self); + } +} + +static void +new_printer_dialog_pre_response_cb (PpNewPrinterDialog *dialog, + const gchar *device_name, + const gchar *device_location, + const gchar *device_make_and_model, + gboolean is_network_device, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + priv->new_printer_name = g_strdup (device_name); + priv->new_printer_location = g_strdup (device_location); + priv->new_printer_make_and_model = g_strdup (device_make_and_model); + priv->new_printer_on_network = is_network_device; + priv->select_new_printer = TRUE; + + actualize_printers_list (self); +} + +static void +new_printer_dialog_response_cb (PpNewPrinterDialog *dialog, + gint response_id, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->pp_new_printer_dialog) + g_clear_object (&priv->pp_new_printer_dialog); + + g_clear_pointer (&priv->new_printer_name, g_free); + g_clear_pointer (&priv->new_printer_location, g_free); + g_clear_pointer (&priv->new_printer_make_and_model, g_free); + + if (response_id == GTK_RESPONSE_REJECT) + { + GtkWidget *message_dialog; + + message_dialog = gtk_message_dialog_new (NULL, + 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + /* Translators: Addition of the new printer failed. */ + _("Failed to add new printer.")); + g_signal_connect (message_dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + gtk_widget_show (message_dialog); + } + + actualize_printers_list (self); +} + +static void +printer_add_cb (GtkToolButton *toolbutton, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *toplevel; + + priv = PRINTERS_PANEL_PRIVATE (self); + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self)); + priv->pp_new_printer_dialog = PP_NEW_PRINTER_DIALOG (pp_new_printer_dialog_new (GTK_WINDOW (toplevel))); + + g_signal_connect (priv->pp_new_printer_dialog, + "pre-response", + G_CALLBACK (new_printer_dialog_pre_response_cb), + self); + + g_signal_connect (priv->pp_new_printer_dialog, + "response", + G_CALLBACK (new_printer_dialog_response_cb), + self); +} + +static void +printer_remove_cb (GtkToolButton *toolbutton, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + char *printer_name = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + printer_name = priv->dests[priv->current_dest].name; + + if (printer_name && printer_delete (printer_name)) + actualize_printers_list (self); +} + +static void +printer_name_edit_cb (GtkWidget *entry, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + const gchar *new_name; + gchar *old_name = NULL; + gint i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + new_name = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry)); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + old_name = priv->dests[priv->current_dest].name; + + if (printer_rename (old_name, new_name)) + { + free_dests (self); + priv->num_dests = cupsGetDests (&priv->dests); + priv->dest_model_names = g_new0 (gchar *, priv->num_dests); + priv->ppd_file_names = g_new0 (gchar *, priv->num_dests); + + for (i = 0; i < priv->num_dests; i++) + if (g_strcmp0 (priv->dests[i].name, new_name) == 0) + { + priv->current_dest = i; + break; + } + } + + actualize_printers_list (self); +} + +static void +printer_location_edit_cb (GtkWidget *entry, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + const gchar *location; + gchar *printer_name = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + location = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry)); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + printer_name = priv->dests[priv->current_dest].name; + + if (printer_name && location && + printer_set_location (printer_name, location)) + actualize_printers_list (self); +} + +static void +set_ppd_cb (gchar *printer_name, + gboolean success, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GList *iter; + + priv = PRINTERS_PANEL_PRIVATE (self); + + for (iter = priv->driver_change_list; iter; iter = iter->next) + { + SetPPDItem *item = (SetPPDItem *) iter->data; + + if (g_strcmp0 (item->printer_name, printer_name) == 0) + { + priv->driver_change_list = g_list_remove_link (priv->driver_change_list, iter); + + g_object_unref (item->cancellable); + g_free (item->printer_name); + g_free (item); + g_list_free (iter); + break; + } + } + + update_sensitivity (self); + + if (success) + { + actualize_printers_list (self); + } + + g_free (printer_name); +} + +static void +select_ppd_manually (GtkMenuItem *menuitem, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkFileFilter *filter; + GtkWidget *dialog; + gchar *printer_name = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + gtk_menu_shell_cancel (GTK_MENU_SHELL (priv->popup_menu)); + + dialog = gtk_file_chooser_dialog_new (_("Select PPD File"), + NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, + _("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)")); + gtk_file_filter_add_pattern (filter, "*.ppd"); + gtk_file_filter_add_pattern (filter, "*.PPD"); + gtk_file_filter_add_pattern (filter, "*.ppd.gz"); + gtk_file_filter_add_pattern (filter, "*.PPD.gz"); + gtk_file_filter_add_pattern (filter, "*.PPD.GZ"); + + gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + gchar *ppd_filename; + + ppd_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + printer_name = priv->dests[priv->current_dest].name; + + if (printer_name && ppd_filename) + { + SetPPDItem *item; + + item = g_new0 (SetPPDItem, 1); + item->printer_name = g_strdup (printer_name); + item->cancellable = g_cancellable_new (); + + priv->driver_change_list = + g_list_prepend (priv->driver_change_list, item); + update_sensitivity (self); + printer_set_ppd_file_async (printer_name, + ppd_filename, + item->cancellable, + set_ppd_cb, + user_data); + } + + g_free (ppd_filename); + } + + gtk_widget_destroy (dialog); +} + +static void +ppd_selection_dialog_response_cb (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + gchar *printer_name = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (response_id == GTK_RESPONSE_OK) + { + gchar *ppd_name; + + ppd_name = pp_ppd_selection_dialog_get_ppd_name (priv->pp_ppd_selection_dialog); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + printer_name = priv->dests[priv->current_dest].name; + + if (printer_name && ppd_name) + { + SetPPDItem *item; + + item = g_new0 (SetPPDItem, 1); + item->printer_name = g_strdup (printer_name); + item->cancellable = g_cancellable_new (); + + priv->driver_change_list = g_list_prepend (priv->driver_change_list, + item); + update_sensitivity (self); + printer_set_ppd_async (printer_name, + ppd_name, + item->cancellable, + set_ppd_cb, + user_data); + } + + g_free (ppd_name); + } + + pp_ppd_selection_dialog_free (priv->pp_ppd_selection_dialog); + priv->pp_ppd_selection_dialog = NULL; +} + +static void +select_ppd_in_dialog (GtkMenuItem *menuitem, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *widget; + gchar *device_id = NULL; + gchar *manufacturer = NULL; + + priv = PRINTERS_PANEL_PRIVATE (self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "main-vbox"); + + if (!priv->pp_ppd_selection_dialog) + { + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests) + { + device_id = + get_ppd_attribute (priv->ppd_file_names[priv->current_dest], + "1284DeviceID"); + + if (device_id) + { + manufacturer = get_tag_value (device_id, "mfg"); + if (!manufacturer) + manufacturer = get_tag_value (device_id, "manufacturer"); + } + + if (manufacturer == NULL) + { + manufacturer = + get_ppd_attribute (priv->ppd_file_names[priv->current_dest], + "Manufacturer"); + } + + if (manufacturer == NULL) + { + manufacturer = g_strdup ("Raw"); + } + } + + priv->pp_ppd_selection_dialog = pp_ppd_selection_dialog_new ( + GTK_WINDOW (gtk_widget_get_toplevel (widget)), + priv->all_ppds_list, + manufacturer, + ppd_selection_dialog_response_cb, + self); + + g_free (manufacturer); + g_free (device_id); + } +} + +static void +set_ppd_from_list (GtkMenuItem *menuitem, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + gchar *printer_name = NULL; + gchar *ppd_name; + + priv = PRINTERS_PANEL_PRIVATE (self); + + ppd_name = (gchar *) g_object_get_data (G_OBJECT (menuitem), "ppd-name"); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + printer_name = priv->dests[priv->current_dest].name; + + if (printer_name && ppd_name) + { + SetPPDItem *item; + + item = g_new0 (SetPPDItem, 1); + item->printer_name = g_strdup (printer_name); + item->cancellable = g_cancellable_new (); + + priv->driver_change_list = g_list_prepend (priv->driver_change_list, + item); + update_sensitivity (self); + printer_set_ppd_async (printer_name, + ppd_name, + item->cancellable, + set_ppd_cb, + user_data); + } +} + +static void +ppd_names_free (gpointer user_data) +{ + PPDName **names = (PPDName **) user_data; + gint i; + + if (names) + { + for (i = 0; names[i]; i++) + { + g_free (names[i]->ppd_name); + g_free (names[i]->ppd_display_name); + g_free (names[i]); + } + + g_free (names); + } +} + +static void +get_ppd_names_cb (PPDName **names, + const gchar *printer_name, + gboolean cancelled, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *informal = NULL; + GtkWidget *placeholders[3]; + GtkWidget *spinner; + gpointer value = NULL; + gboolean found = FALSE; + PPDName **hash_names = NULL; + GList *children, *iter; + gint i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + priv->getting_ppd_names = FALSE; + + for (i = 0; i < 3; i++) + placeholders[i] = NULL; + + children = gtk_container_get_children (GTK_CONTAINER (priv->popup_menu)); + if (children) + { + for (iter = children; iter; iter = iter->next) + { + if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"), + "informal") == 0) + informal = GTK_WIDGET (iter->data); + else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"), + "placeholder1") == 0) + placeholders[0] = GTK_WIDGET (iter->data); + else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"), + "placeholder2") == 0) + placeholders[1] = GTK_WIDGET (iter->data); + else if (g_strcmp0 ((gchar *) g_object_get_data (G_OBJECT (iter->data), "purpose"), + "placeholder3") == 0) + placeholders[2] = GTK_WIDGET (iter->data); + } + + g_list_free (children); + } + + if (!priv->preferred_drivers) + { + priv->preferred_drivers = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, ppd_names_free); + } + + if (!cancelled && + !g_hash_table_lookup_extended (priv->preferred_drivers, + printer_name, NULL, NULL)) + g_hash_table_insert (priv->preferred_drivers, g_strdup (printer_name), names); + + if (priv->preferred_drivers && + g_hash_table_lookup_extended (priv->preferred_drivers, + printer_name, NULL, &value)) + { + hash_names = (PPDName **) value; + if (hash_names) + { + for (i = 0; hash_names[i]; i++) + { + if (placeholders[i]) + { + gtk_menu_item_set_label (GTK_MENU_ITEM (placeholders[i]), + hash_names[i]->ppd_display_name); + g_object_set_data_full (G_OBJECT (placeholders[i]), + "ppd-name", + g_strdup (hash_names[i]->ppd_name), + g_free); + g_signal_connect (placeholders[i], + "activate", + G_CALLBACK (set_ppd_from_list), + self); + gtk_widget_set_sensitive (GTK_WIDGET (placeholders[i]), TRUE); + gtk_widget_show (placeholders[i]); + } + } + + found = TRUE; + } + else + { + found = FALSE; + } + } + + if (informal) + { + gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (informal), FALSE); + + spinner = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (informal)); + if (spinner) + gtk_spinner_stop (GTK_SPINNER (spinner)); + + if (found) + gtk_widget_hide (informal); + else + gtk_menu_item_set_label (GTK_MENU_ITEM (informal), _("No suitable driver found")); + } + + gtk_widget_show_all (priv->popup_menu); + + update_sensitivity (self); +} + +static void +popup_menu_done (GtkMenuShell *menushell, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->get_ppd_name_cancellable) + { + g_cancellable_cancel (priv->get_ppd_name_cancellable); + g_object_unref (priv->get_ppd_name_cancellable); + priv->get_ppd_name_cancellable = NULL; + } +} + +static void +popup_model_menu_cb (GtkButton *button, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *spinner; + GtkWidget *item; + + priv = PRINTERS_PANEL_PRIVATE (self); + + priv->popup_menu = gtk_menu_new (); + g_signal_connect (priv->popup_menu, + "selection-done", + G_CALLBACK (popup_menu_done), + user_data); + + /* + * These placeholders are a workaround for a situation + * when we want to actually append new menu item in a callback. + * But unfortunately it is not possible to connect to "activate" + * signal of such menu item (appended after gtk_menu_popup()). + */ + item = gtk_image_menu_item_new_with_label (""); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("placeholder1"), g_free); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + gtk_widget_set_no_show_all (item, TRUE); + gtk_widget_hide (item); + + item = gtk_image_menu_item_new_with_label (""); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("placeholder2"), g_free); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + gtk_widget_set_no_show_all (item, TRUE); + gtk_widget_hide (item); + + item = gtk_image_menu_item_new_with_label (""); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("placeholder3"), g_free); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + gtk_widget_set_no_show_all (item, TRUE); + gtk_widget_hide (item); + + item = gtk_image_menu_item_new_with_label (_("Searching for preferred drivers...")); + spinner = gtk_spinner_new (); + gtk_spinner_start (GTK_SPINNER (spinner)); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), spinner); + gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("informal"), g_free); + gtk_widget_set_sensitive (item, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + gtk_widget_set_no_show_all (item, TRUE); + gtk_widget_show (item); + + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + + item = gtk_menu_item_new_with_label (_("Select from database...")); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("ppd-select"), g_free); + g_signal_connect (item, "activate", G_CALLBACK (select_ppd_in_dialog), self); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + + item = gtk_menu_item_new_with_label (_("Provide PPD File...")); + g_object_set_data_full (G_OBJECT (item), "purpose", + g_strdup ("ppdfile-select"), g_free); + g_signal_connect (item, "activate", G_CALLBACK (select_ppd_manually), self); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item); + + gtk_widget_show_all (priv->popup_menu); + + gtk_menu_popup (GTK_MENU (priv->popup_menu), + NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + if (priv->preferred_drivers && + g_hash_table_lookup_extended (priv->preferred_drivers, + priv->dests[priv->current_dest].name, + NULL, NULL)) + { + get_ppd_names_cb (NULL, + priv->dests[priv->current_dest].name, + FALSE, + user_data); + } + else + { + priv->get_ppd_name_cancellable = g_cancellable_new (); + priv->getting_ppd_names = TRUE; + get_ppd_names_async (priv->dests[priv->current_dest].name, + 3, + priv->get_ppd_name_cancellable, + get_ppd_names_cb, + user_data); + + update_sensitivity (self); + } + } +} + +static void +pp_maintenance_command_execute_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpMaintenanceCommand *command = (PpMaintenanceCommand *) source_object; + GError *error = NULL; + + pp_maintenance_command_execute_finish (command, res, &error); + + g_object_unref (command); +} + +static void +test_page_cb (GtkButton *button, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + cups_ptype_t type = 0; + const gchar *printer_type = NULL; + gchar *printer_name = NULL; + gint i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + printer_name = priv->dests[priv->current_dest].name; + printer_type = cupsGetOption ("printer-type", + priv->dests[priv->current_dest].num_options, + priv->dests[priv->current_dest].options); + if (printer_type) + type = atoi (printer_type); + } + + if (printer_name) + { + const gchar *const dirs[] = { "/usr/share/cups", + "/usr/local/share/cups", + NULL }; + const gchar *testprint[] = { "%s/data/testprint", + "%s/data/testprint.ps", + NULL }; + const gchar **pattern; + const gchar *datadir = NULL; + http_t *http = NULL; + gchar *printer_uri = NULL; + gchar *filename = NULL; + gchar *resource = NULL; + ipp_t *response = NULL; + ipp_t *request; + + if ((datadir = getenv ("CUPS_DATADIR")) != NULL) + { + for (pattern = testprint; *pattern != NULL; pattern++) + { + filename = g_strdup_printf (*pattern, datadir); + if (g_access (filename, R_OK) == 0) + break; + else + { + g_free (filename); + filename = NULL; + } + } + } + else + { + for (i = 0; (datadir = dirs[i]) != NULL && filename == NULL; i++) + { + for (pattern = testprint; *pattern != NULL; pattern++) + { + filename = g_strdup_printf (*pattern, datadir); + if (g_access (filename, R_OK) == 0) + break; + else + { + g_free (filename); + filename = NULL; + } + } + } + } + + if (filename) + { + if (type & CUPS_PRINTER_CLASS) + { + printer_uri = g_strdup_printf ("ipp://localhost/classes/%s", printer_name); + resource = g_strdup_printf ("/classes/%s", printer_name); + } + else + { + printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", printer_name); + resource = g_strdup_printf ("/printers/%s", printer_name); + } + + http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ()); + if (http) + { + request = ippNewRequest (IPP_PRINT_JOB); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser ()); + ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, + /* Translators: Name of job which makes printer to print test page */ + "job-name", NULL, _("Test page")); + response = cupsDoFileRequest (http, request, resource, filename); + httpClose (http); + } + + if (response) + { + if (ippGetState (response) == IPP_ERROR) + g_warning ("An error has occured during printing of test page."); + ippDelete (response); + } + + g_free (filename); + g_free (printer_uri); + g_free (resource); + } + else + { + PpMaintenanceCommand *command; + + command = pp_maintenance_command_new (printer_name, + "PrintSelfTestPage", + /* Translators: Name of job which makes printer to print test page */ + _("Test page")); + + pp_maintenance_command_execute_async (command, NULL, pp_maintenance_command_execute_cb, self); + } + } +} + +static void +update_sensitivity (gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + GtkTreeSelection *selection; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + cups_ptype_t type = 0; + GtkTreeModel *model; + GtkTreeView *treeview; + GtkTreeIter tree_iter; + const char *cups_server = NULL; + GtkWidget *widget; + gboolean is_authorized; + gboolean is_discovered = FALSE; + gboolean is_class = FALSE; + gboolean is_changing_driver = FALSE; + gboolean printer_selected; + gboolean local_server = TRUE; + gboolean no_cups = FALSE; + gboolean is_new = FALSE; + gboolean already_present_local; + GList *iter; + gchar *current_printer_name = NULL; + gint i; + + priv = PRINTERS_PANEL_PRIVATE (self); + + is_authorized = + priv->permission && + g_permission_get_allowed (G_PERMISSION (priv->permission)) && + priv->lockdown_settings && + !g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup"); + + printer_selected = priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL; + + if (printer_selected) + { + for (i = 0; i < priv->dests[priv->current_dest].num_options; i++) + { + if (g_strcmp0 (priv->dests[priv->current_dest].options[i].name, "printer-type") == 0) + { + type = atoi (priv->dests[priv->current_dest].options[i].value); + is_discovered = type & CUPS_PRINTER_DISCOVERED; + is_class = type & CUPS_PRINTER_CLASS; + break; + } + } + + for (iter = priv->driver_change_list; iter; iter = iter->next) + { + SetPPDItem *item = (SetPPDItem *) iter->data; + + if (g_strcmp0 (item->printer_name, priv->dests[priv->current_dest].name) == 0) + { + is_changing_driver = TRUE; + } + } + } + + treeview = (GtkTreeView*) + gtk_builder_get_object (priv->builder, "printers-treeview"); + + selection = gtk_tree_view_get_selection (treeview); + if (selection && + gtk_tree_selection_get_selected (selection, &model, &tree_iter)) + { + gtk_tree_model_get (model, &tree_iter, + PRINTER_NAME_COLUMN, ¤t_printer_name, + -1); + } + + if (priv->new_printer_name && + g_strcmp0 (priv->new_printer_name, current_printer_name) == 0) + { + printer_selected = TRUE; + is_discovered = FALSE; + is_class = FALSE; + is_new = TRUE; + } + + g_free (current_printer_name); + + cups_server = cupsServer (); + if (cups_server && + g_ascii_strncasecmp (cups_server, "localhost", 9) != 0 && + g_ascii_strncasecmp (cups_server, "127.0.0.1", 9) != 0 && + g_ascii_strncasecmp (cups_server, "::1", 3) != 0 && + cups_server[0] != '/') + local_server = FALSE; + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "notebook"); + if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == NOTEBOOK_NO_CUPS_PAGE) + no_cups = TRUE; + + already_present_local = local_server && !is_discovered && is_authorized && !is_new; + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button"); + gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button2"); + gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-remove-button"); + gtk_widget_set_sensitive (widget, already_present_local && printer_selected && !no_cups); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-disable-switch"); + gtk_widget_set_sensitive (widget, already_present_local); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-default-check-button"); + gtk_widget_set_sensitive (widget, is_authorized && !is_new); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "print-test-page-button"); + gtk_widget_set_sensitive (widget, printer_selected && !is_new); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-options-button"); + gtk_widget_set_sensitive (widget, printer_selected && local_server && !is_discovered && + !priv->pp_options_dialog && !is_new); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-jobs-button"); + gtk_widget_set_sensitive (widget, printer_selected && !is_new); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-icon"); + gtk_widget_set_sensitive (widget, printer_selected); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-name-label"); + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-location-label"); + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-model-notebook"); + if (is_changing_driver) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2); + } + else + { + if (already_present_local && !is_class && !priv->getting_ppd_names) + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0); + else + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1); + } +} + +static void +on_permission_changed (GPermission *permission, + GParamSpec *pspec, + gpointer data) +{ + update_sensitivity (data); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + if (g_str_equal (key, "disable-print-setup") == FALSE) + return; + + priv = PRINTERS_PANEL_PRIVATE (self); + +#if 0 + /* FIXME */ + gtk_widget_set_sensitive (priv->lock_button, + !g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup")); +#endif + + on_permission_changed (priv->permission, NULL, user_data); +} + +static void +printer_options_response_cb (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + pp_options_dialog_free (priv->pp_options_dialog); + priv->pp_options_dialog = NULL; + update_sensitivity (self); + + if (response_id == GTK_RESPONSE_OK) + actualize_printers_list (self); +} + +static void +printer_options_cb (GtkToolButton *toolbutton, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *widget; + gboolean is_authorized; + + priv = PRINTERS_PANEL_PRIVATE (self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "main-vbox"); + + is_authorized = + priv->permission && + g_permission_get_allowed (G_PERMISSION (priv->permission)) && + priv->lockdown_settings && + !g_settings_get_boolean (priv->lockdown_settings, "disable-print-setup"); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + { + priv->pp_options_dialog = pp_options_dialog_new ( + GTK_WINDOW (gtk_widget_get_toplevel (widget)), + printer_options_response_cb, + self, + priv->dests[priv->current_dest].name, + is_authorized); + update_sensitivity (self); + } +} + +static gboolean +cups_status_check (gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + gboolean result = TRUE; + http_t *http; + + priv = self->priv = PRINTERS_PANEL_PRIVATE (self); + + http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ()); + if (http) + { + httpClose (http); + actualize_printers_list (self); + attach_to_cups_notifier (self); + priv->cups_status_check_id = 0; + result = FALSE; + } + + return result; +} + +static void +get_all_ppds_async_cb (PPDList *ppds, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = self->priv = PRINTERS_PANEL_PRIVATE (self); + + priv->all_ppds_list = ppds; + + if (priv->pp_ppd_selection_dialog) + pp_ppd_selection_dialog_set_ppd_list (priv->pp_ppd_selection_dialog, + priv->all_ppds_list); + + g_object_unref (priv->get_all_ppds_cancellable); + priv->get_all_ppds_cancellable = NULL; +} + +static void +update_label_padding (GtkWidget *widget, + GtkAllocation *allocation, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkAllocation allocation1, allocation2; + GtkWidget *label; + GtkWidget *sublabel; + gint offset; + gint pad; + + priv = PRINTERS_PANEL_PRIVATE (self); + + sublabel = gtk_bin_get_child (GTK_BIN (widget)); + if (sublabel) + { + gtk_widget_get_allocation (widget, &allocation1); + gtk_widget_get_allocation (sublabel, &allocation2); + + offset = allocation2.x - allocation1.x; + + label = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-label"); + + gtk_misc_get_padding (GTK_MISC (label), &pad, NULL); + if (offset != pad) + gtk_misc_set_padding (GTK_MISC (label), offset, 0); + } +} + +static void +jobs_dialog_response_cb (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + + priv = PRINTERS_PANEL_PRIVATE (self); + + pp_jobs_dialog_free (priv->pp_jobs_dialog); + priv->pp_jobs_dialog = NULL; +} + +static void +printer_jobs_cb (GtkToolButton *toolbutton, + gpointer user_data) +{ + CcPrintersPanelPrivate *priv; + CcPrintersPanel *self = (CcPrintersPanel*) user_data; + GtkWidget *widget; + + priv = PRINTERS_PANEL_PRIVATE (self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "main-vbox"); + + if (priv->current_dest >= 0 && + priv->current_dest < priv->num_dests && + priv->dests != NULL) + priv->pp_jobs_dialog = pp_jobs_dialog_new ( + GTK_WINDOW (gtk_widget_get_toplevel (widget)), + jobs_dialog_response_cb, + self, + priv->dests[priv->current_dest].name); +} + +static void +cc_printers_panel_init (CcPrintersPanel *self) +{ + CcPrintersPanelPrivate *priv; + GtkWidget *top_widget; + GtkWidget *widget; + GError *error = NULL; + http_t *http; + gchar *objects[] = { "main-vbox", NULL }; + GtkStyleContext *context; + guint builder_result; + + priv = self->priv = PRINTERS_PANEL_PRIVATE (self); + + /* initialize main data structure */ + priv->builder = gtk_builder_new (); + priv->dests = NULL; + priv->dest_model_names = NULL; + priv->ppd_file_names = NULL; + priv->num_dests = 0; + priv->current_dest = -1; + + priv->num_jobs = 0; + + priv->pp_new_printer_dialog = NULL; + priv->pp_options_dialog = NULL; + + priv->subscription_id = 0; + priv->cups_status_check_id = 0; + priv->subscription_renewal_id = 0; + priv->cups_proxy = NULL; + priv->cups_bus_connection = NULL; + priv->dbus_subscription_id = 0; + + priv->new_printer_name = NULL; + priv->new_printer_location = NULL; + priv->new_printer_make_and_model = NULL; + priv->new_printer_on_network = FALSE; + priv->select_new_printer = FALSE; + + priv->permission = NULL; + priv->lockdown_settings = NULL; + + priv->getting_ppd_names = FALSE; + + priv->all_ppds_list = NULL; + priv->get_all_ppds_cancellable = NULL; + + priv->preferred_drivers = NULL; + + builder_result = gtk_builder_add_objects_from_file (priv->builder, + DATADIR"/printers.ui", + objects, &error); + + if (builder_result == 0) + { + /* Translators: The XML file containing user interface can not be loaded */ + g_warning (_("Could not load ui: %s"), error->message); + g_error_free (error); + return; + } + + /* add the top level widget */ + top_widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "main-vbox"); + + /* connect signals */ + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-add-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-add-button2"); + g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-remove-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (printer_remove_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-disable-switch"); + g_signal_connect (widget, "notify::active", G_CALLBACK (printer_disable_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "supply-drawing-area"); + g_signal_connect (widget, "draw", G_CALLBACK (supply_levels_draw_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-default-check-button"); + g_signal_connect (widget, "toggled", G_CALLBACK (printer_set_default_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "print-test-page-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (test_page_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-jobs-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (printer_jobs_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-options-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (printer_options_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-name-label"); + g_signal_connect (widget, "editing-done", G_CALLBACK (printer_name_edit_cb), self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-location-label"); + g_signal_connect (widget, "editing-done", G_CALLBACK (printer_location_edit_cb), self); + + priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + if (priv->lockdown_settings) + g_signal_connect (priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-model-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (popup_model_menu_cb), self); + g_signal_connect (widget, "size-allocate", G_CALLBACK (update_label_padding), self); + + + /* Set junctions */ + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printers-scrolledwindow"); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printers-toolbar"); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + + /* Make model label and ip-address label selectable */ + widget = (GtkWidget*) + gtk_builder_get_object (priv->builder, "printer-ip-address-label"); + cc_editable_entry_set_selectable (CC_EDITABLE_ENTRY (widget), TRUE); + + + /* Add unlock button */ + priv->permission = (GPermission *)polkit_permission_new_sync ( + "org.opensuse.cupspkhelper.mechanism.all-edit", NULL, NULL, NULL); + if (priv->permission != NULL) + { + g_signal_connect (priv->permission, "notify", + G_CALLBACK (on_permission_changed), self); + on_permission_changed (priv->permission, NULL, self); + } + else + g_warning ("Your system does not have the cups-pk-helper's policy \ +\"org.opensuse.cupspkhelper.mechanism.all-edit\" installed. \ +Please check your installation"); + + gtk_style_context_get_background_color (gtk_widget_get_style_context (top_widget), + GTK_STATE_FLAG_NORMAL, + &priv->background_color); + + populate_printers_list (self); + attach_to_cups_notifier (self); + + priv->get_all_ppds_cancellable = g_cancellable_new (); + get_all_ppds_async (priv->get_all_ppds_cancellable, + get_all_ppds_async_cb, + self); + + http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ()); + if (!http) + { + priv->cups_status_check_id = + g_timeout_add_seconds (CUPS_STATUS_CHECK_INTERVAL, cups_status_check, self); + } + else + httpClose (http); + + gtk_container_add (GTK_CONTAINER (self), top_widget); + gtk_widget_show_all (GTK_WIDGET (self)); +} + +void +cc_printers_panel_register (GIOModule *module) +{ + cc_printers_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_PRINTERS_PANEL, + "printers", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/screen/cc-screen-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/screen/cc-screen-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,561 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "cc-screen-panel.h" + +CC_PANEL_REGISTER (CcScreenPanel, cc_screen_panel) + +#define SCREEN_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SCREEN_PANEL, CcScreenPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +struct _CcScreenPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *session_settings; + GSettings *lockdown_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + gboolean setting_brightness; +}; + + +static void +cc_screen_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_dispose (GObject *object) +{ + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (object)->priv; + + if (priv->lock_settings) + { + g_object_unref (priv->lock_settings); + priv->lock_settings = NULL; + } + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->session_settings) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + G_OBJECT_CLASS (cc_screen_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "lock-delay") == FALSE) + return; +} + +static void +update_lock_screen_sensitivity (CcScreenPanel *self) +{ + GtkWidget *widget; + gboolean locked; + + widget = WID ("screen_lock_main_box"); + locked = g_settings_get_boolean (self->priv->lockdown_settings, "disable-lock-screen"); + gtk_widget_set_sensitive (widget, !locked); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "disable-lock-screen") == FALSE) + return; + + update_lock_screen_sensitivity (panel); +} + +static const char * +cc_screen_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/prefs-display"; +} + +static void +cc_screen_panel_class_init (CcScreenPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcScreenPanelPrivate)); + + object_class->get_property = cc_screen_panel_get_property; + object_class->set_property = cc_screen_panel_set_property; + object_class->dispose = cc_screen_panel_dispose; + + panel_class->get_help_uri = cc_screen_panel_get_help_uri; +} + +static void +set_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* not setting, so pay attention to changed signals */ + priv->setting_brightness = FALSE; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + g_printerr ("Error setting brightness: %s\n", error->message); + g_error_free (error); + return; + } +} + +static void +brightness_slider_value_changed_cb (GtkRange *range, gpointer user_data) +{ + guint percentage; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* do not loop */ + if (priv->setting_brightness) + return; + + priv->setting_brightness = TRUE; + + /* push this to g-p-m */ + percentage = (guint) gtk_range_get_value (range); + g_dbus_proxy_call (priv->proxy, + "SetPercentage", + g_variant_new ("(u)", + percentage), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + set_brightness_cb, + user_data); +} + +static void +get_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + guint brightness; + GtkRange *range; + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + /* We got cancelled, so we're probably exiting */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + gtk_widget_hide (WID ("screen_brightness_hscale")); + gtk_widget_hide (WID ("screen_auto_reduce_checkbutton")); + gtk_widget_hide (WID ("brightness-frame")); + g_object_set (G_OBJECT (WID ("turn-off-alignment")), "left-padding", 0, NULL); + + if (error->message && + strstr (error->message, "No backlight devices present") == NULL) + { + g_warning ("Error getting brightness: %s", error->message); + } + g_error_free (error); + return; + } + + /* set the slider */ + g_variant_get (result, + "(u)", + &brightness); + range = GTK_RANGE (WID ("screen_brightness_hscale")); + gtk_range_set_range (range, 0, 100); + gtk_range_set_increments (range, 1, 10); + gtk_range_set_value (range, brightness); + g_signal_connect (range, + "value-changed", + G_CALLBACK (brightness_slider_value_changed_cb), + user_data); + g_variant_unref (result); +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + if (g_strcmp0 (signal_name, "Changed") == 0) + { + /* changed, but ignoring */ + if (self->priv->setting_brightness) + return; + + /* retrieve the value again from g-s-d */ + g_dbus_proxy_call (self->priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + self->priv->cancellable, + get_brightness_cb, + user_data); + } +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (priv->proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* we want to change the bar if the user presses brightness buttons */ + g_signal_connect (priv->proxy, + "g-signal", + G_CALLBACK (on_signal), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + priv->cancellable, + get_brightness_cb, + user_data); +} + +static void +set_idle_delay_from_dpms (CcScreenPanel *self, + int value) +{ + guint off_delay; + + off_delay = 0; + + if (value > 0) + off_delay = (guint) value; + + g_settings_set (self->priv->session_settings, "idle-delay", "u", off_delay); +} + +static void +dpms_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); + g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + + set_idle_delay_from_dpms (self, value); +} + +static void +lock_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint delay; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &delay, + -1); + g_settings_set (self->priv->lock_settings, "lock-delay", "u", delay); +} + +static void +set_dpms_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the AC setting */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +set_lock_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the lock setting */ + g_settings_get (self->priv->lock_settings, "lock-delay", "u", &value); + + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +cc_screen_panel_init (CcScreenPanel *self) +{ + GError *error; + GtkWidget *widget; + + self->priv = SCREEN_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/screen.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->cancellable = g_cancellable_new (); + + /* get initial brightness version */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + self->priv->cancellable, + got_power_proxy_cb, + self); + + self->priv->lock_settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_signal_connect (self->priv->lock_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + self->priv->session_settings = g_settings_new ("org.gnome.desktop.session"); + self->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect (self->priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + /* bind the auto dim checkbox */ + widget = WID ("screen_auto_reduce_checkbutton"); + g_settings_bind (self->priv->gsd_settings, + "idle-dim-battery", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* display off time */ + widget = WID ("screen_brightness_combobox"); + set_dpms_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (dpms_combo_changed_cb), + self); + + /* bind the screen lock checkbox */ + widget = WID ("screen_lock_on_switch"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* lock time */ + widget = WID ("screen_lock_combobox"); + set_lock_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (lock_combo_changed_cb), + self); + + widget = WID ("screen_lock_hbox"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "sensitive", + G_SETTINGS_BIND_GET); + + widget = WID ("show_notifications_check"); + g_settings_bind (self->priv->lock_settings, + "show-notifications", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + update_lock_screen_sensitivity (self); + + widget = WID ("screen_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + g_object_set (self, "valign", GTK_ALIGN_START, NULL); +} + +void +cc_screen_panel_register (GIOModule *module) +{ + cc_screen_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SCREEN_PANEL, + "screen", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/sound/cc-sound-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/sound/cc-sound-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/sound/cc-sound-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/sound/cc-sound-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cc-sound-panel.h" +#include "gvc-mixer-dialog.h" + +CC_PANEL_REGISTER (CcSoundPanel, cc_sound_panel) + +enum { + PROP_0, + PROP_ARGV +}; + +static void cc_sound_panel_finalize (GObject *object); + +static void +cc_sound_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + CcSoundPanel *self = CC_SOUND_PANEL (object); + + switch (property_id) { + case PROP_ARGV: { + gchar **args; + + args = g_value_get_boxed (value); + + if (args && args[0]) { + gvc_mixer_dialog_set_page (self->dialog, args[0]); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static const char * +cc_sound_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/media#sound"; +} + +static void +cc_sound_panel_class_init (CcSoundPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = cc_sound_panel_get_help_uri; + + object_class->finalize = cc_sound_panel_finalize; + object_class->set_property = cc_sound_panel_set_property; + + g_object_class_override_property (object_class, PROP_ARGV, "argv"); +} + +static void +cc_sound_panel_finalize (GObject *object) +{ + CcSoundPanel *panel = CC_SOUND_PANEL (object); + + if (panel->dialog != NULL) + panel->dialog = NULL; + if (panel->connecting_label != NULL) + panel->connecting_label = NULL; + if (panel->control != NULL) { + g_object_unref (panel->control); + panel->control = NULL; + } + + G_OBJECT_CLASS (cc_sound_panel_parent_class)->finalize (object); +} + +static void +cc_sound_panel_init (CcSoundPanel *self) +{ + gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), + ICON_DATA_DIR); + gtk_window_set_default_icon_name ("multimedia-volume-control"); + + self->control = gvc_mixer_control_new ("GNOME Volume Control Dialog"); + gvc_mixer_control_open (self->control); + self->dialog = gvc_mixer_dialog_new (self->control); + gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->dialog)); + gtk_widget_show (GTK_WIDGET (self->dialog)); +} + +void +cc_sound_panel_register (GIOModule *module) +{ + cc_sound_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SOUND_PANEL, + "sound", 0); +} + +/* GIO extension stuff */ +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + /* register the panel */ + cc_sound_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/universal-access/cc-ua-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/universal-access/cc-ua-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/universal-access/cc-ua-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/universal-access/cc-ua-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,696 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Thomas Wood + * Rodrigo Moya + * + */ + +#include + +#include +#include +#include +#include "cc-ua-panel.h" + +#include "zoom-options.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +#define DPI_FACTOR_LARGE 1.25 +#define DPI_FACTOR_NORMAL 1.0 + +#define HIGH_CONTRAST_THEME "HighContrast" +#define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" +#define KEY_GTK_THEME "gtk-theme" +#define KEY_ICON_THEME "icon-theme" + + +CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel) + +#define UA_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_UA_PANEL, CcUaPanelPrivate)) + +struct _CcUaPanelPrivate +{ + GtkBuilder *builder; + GSettings *wm_settings; + GSettings *interface_settings; + GSettings *kb_settings; + GSettings *mouse_settings; + GSettings *application_settings; + GSettings *mediakeys_settings; + + ZoomOptions *zoom_options; + guint shell_watch_id; +}; + + +static void +cc_ua_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_dispose (GObject *object) +{ + CcUaPanelPrivate *priv = CC_UA_PANEL (object)->priv; + + if (priv->shell_watch_id) + { + g_bus_unwatch_name (priv->shell_watch_id); + priv->shell_watch_id = 0; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->wm_settings) + { + g_object_unref (priv->wm_settings); + priv->wm_settings = NULL; + } + + if (priv->interface_settings) + { + g_object_unref (priv->interface_settings); + priv->interface_settings = NULL; + } + + if (priv->kb_settings) + { + g_object_unref (priv->kb_settings); + priv->kb_settings = NULL; + } + + if (priv->mouse_settings) + { + g_object_unref (priv->mouse_settings); + priv->mouse_settings = NULL; + } + + if (priv->application_settings) + { + g_object_unref (priv->application_settings); + priv->application_settings = NULL; + } + + if (priv->mediakeys_settings) + { + g_object_unref (priv->mediakeys_settings); + priv->mediakeys_settings = NULL; + } + + if (priv->zoom_options) + { + g_object_unref (priv->zoom_options); + priv->zoom_options = NULL; + } + + G_OBJECT_CLASS (cc_ua_panel_parent_class)->dispose (object); +} + +static void +cc_ua_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_ua_panel_parent_class)->finalize (object); +} + +static const char * +cc_ua_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/a11y"; +} + +static void +cc_ua_panel_class_init (CcUaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcUaPanelPrivate)); + + panel_class->get_help_uri = cc_ua_panel_get_help_uri; + + object_class->get_property = cc_ua_panel_get_property; + object_class->set_property = cc_ua_panel_set_property; + object_class->dispose = cc_ua_panel_dispose; + object_class->finalize = cc_ua_panel_finalize; +} + +static gchar *sticky_keys_section[] = { + "typing_sticky_keys_disable_two_keys_checkbutton", + "typing_sticky_keys_beep_modifier_checkbutton", + NULL +}; + +static gchar *slow_keys_section[]= { + "typing_slowkeys_delay_box", + "typing_slow_keys_beeb_box", + NULL +}; + +static gchar *bounce_keys_section[] = { + "typing_bouncekeys_delay_box", + "typing_bounce_keys_beep_rejected_checkbutton", + NULL +}; + +static gchar *secondary_click_section[] = { + "pointing_secondary_click_scale_box", + NULL +}; + +static gchar *dwell_click_section[] = { + "pointing_hover_click_delay_scale_box", + "pointing_hover_click_threshold_scale_box", + NULL +}; + +static gchar *visual_alerts_section[] = { + "hearing_test_flash_button", + "hearing_flash_window_title_button", + "hearing_flash_screen_button", + NULL +}; + +/* zoom options dialog */ +static void +zoom_options_launch_cb (GtkWidget *options_button, CcUaPanel *self) +{ + if (self->priv->zoom_options == NULL) + self->priv->zoom_options = zoom_options_new (); + + if (self->priv->zoom_options != NULL) + zoom_options_set_parent (self->priv->zoom_options, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); +} + +static void +cc_ua_panel_section_switched (GObject *object, + GParamSpec *pspec, + GtkBuilder *builder) +{ + GtkWidget *w; + gboolean enabled; + gchar **widgets, **s; + + widgets = g_object_get_data (object, "section-widgets"); + + g_object_get (object, "active", &enabled, NULL); + + for (s = widgets; *s; s++) + { + w = WID (builder, *s); + gtk_widget_set_sensitive (w, enabled); + } +} + +static void +settings_on_off_editor_new (CcUaPanelPrivate *priv, + GSettings *settings, + const gchar *key, + GtkWidget *widget, + gchar **section) +{ + /* set data to enable/disable the section this on/off switch controls */ + if (section) + { + g_object_set_data (G_OBJECT (widget), "section-widgets", section); + g_signal_connect (widget, "notify::active", + G_CALLBACK (cc_ua_panel_section_switched), + priv->builder); + } + + /* set up the boolean editor */ + g_settings_bind (settings, key, widget, "active", G_SETTINGS_BIND_DEFAULT); +} + +/* seeing section */ + +static void +cc_ua_panel_set_shortcut_label (CcUaPanel *self, + const char *label, + const char *key) +{ + GtkWidget *widget; + char *value; + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + widget = WID (self->priv->builder, label); + value = g_settings_get_string (self->priv->mediakeys_settings, key); + + if (value == NULL || *value == '\0') { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + g_free (value); + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +shell_vanished_cb (GDBusConnection *connection, + const gchar *name, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_hide (WID (priv->builder, "zoom_label_box")); + gtk_widget_hide (WID (priv->builder, "zoom_value_box")); +} + +static void +shell_appeared_cb (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_show (WID (priv->builder, "zoom_label_box")); + gtk_widget_show (WID (priv->builder, "zoom_value_box")); +} + +static gboolean +get_large_text_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + gdouble factor; + gboolean large; + + factor = g_variant_get_double (variant); + large = factor > DPI_FACTOR_NORMAL; + g_value_set_boolean (value, large); + + return TRUE; +} + +static GVariant * +set_large_text_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean large; + GSettings *settings = user_data; + GVariant *ret = NULL; + + large = g_value_get_boolean (value); + if (large) + ret = g_variant_new_double (DPI_FACTOR_LARGE); + else + g_settings_reset (settings, KEY_TEXT_SCALING_FACTOR); + + return ret; +} + +static gboolean +get_contrast_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + const char *theme; + gboolean hc; + + theme = g_variant_get_string (variant, NULL); + hc = (g_strcmp0 (theme, HIGH_CONTRAST_THEME) == 0); + g_value_set_boolean (value, hc); + + return TRUE; +} + +static GVariant * +set_contrast_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean hc; + GSettings *settings = user_data; + GVariant *ret = NULL; + + hc = g_value_get_boolean (value); + if (hc) + { + ret = g_variant_new_string (HIGH_CONTRAST_THEME); + g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); + } + else + { + g_settings_reset (settings, KEY_GTK_THEME); + g_settings_reset (settings, KEY_ICON_THEME); + } + + return ret; +} + +static void +cc_ua_panel_init_seeing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + g_settings_bind_with_mapping (priv->interface_settings, KEY_GTK_THEME, + WID (priv->builder, "seeing_contrast_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_contrast_mapping, + set_contrast_mapping, + priv->interface_settings, + NULL); + g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR, + WID (priv->builder, "seeing_large_text_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_large_text_mapping, + set_large_text_mapping, + priv->interface_settings, + NULL); + + g_settings_bind (priv->kb_settings, "togglekeys-enable", + WID (priv->builder, "seeing_toggle_keys_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) shell_appeared_cb, + (GBusNameVanishedCallback) shell_vanished_cb, + self, + NULL); + g_signal_connect (WID (priv->builder, "seeing_zoom_preferences_button"), + "clicked", + G_CALLBACK (zoom_options_launch_cb), self); + g_settings_bind (priv->application_settings, "screen-magnifier-enabled", + WID (priv->builder, "seeing_zoom_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + settings_on_off_editor_new (priv, priv->application_settings, + "screen-reader-enabled", + WID (priv->builder, "seeing_reader_switch"), + NULL); + + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_enable_keybinding_label", "magnifier"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_in_keybinding_label", "magnifier-zoom-in"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_out_keybinding_label", "magnifier-zoom-out"); + cc_ua_panel_set_shortcut_label (self, "seeing_reader_enable_keybinding_label", "screenreader"); +} + + +/* hearing/sound section */ +static void +visual_bell_type_notify_cb (GSettings *settings, + const gchar *key, + CcUaPanel *panel) +{ + GtkWidget *widget; + GDesktopVisualBellType type; + + type = g_settings_get_enum (panel->priv->wm_settings, "visual-bell-type"); + + if (type == G_DESKTOP_VISUAL_BELL_FRAME_FLASH) + widget = WID (panel->priv->builder, "hearing_flash_window_title_button"); + else + widget = WID (panel->priv->builder, "hearing_flash_screen_button"); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); +} + +static void +visual_bell_type_toggle_cb (GtkWidget *button, + CcUaPanel *panel) +{ + gboolean frame_flash; + GDesktopVisualBellType type; + + frame_flash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (frame_flash) + type = G_DESKTOP_VISUAL_BELL_FRAME_FLASH; + else + type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH; + g_settings_set_enum (panel->priv->wm_settings, "visual-bell-type", type); +} + +static gboolean +hearing_sound_preferences_clicked (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_hearing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* set the initial visual bell values */ + visual_bell_type_notify_cb (NULL, NULL, self); + + /* and listen */ + w = WID (priv->builder, "hearing_visual_alerts_switch"); + settings_on_off_editor_new (priv, priv->wm_settings, "visual-bell", w, visual_alerts_section); + + g_signal_connect (priv->wm_settings, "changed::visual-bell-type", + G_CALLBACK (visual_bell_type_notify_cb), self); + g_signal_connect (WID (priv->builder, "hearing_flash_window_title_button"), + "toggled", G_CALLBACK (visual_bell_type_toggle_cb), self); + + /* test flash */ + g_signal_connect (WID (priv->builder, "hearing_test_flash_button"), + "clicked", G_CALLBACK (gdk_beep), NULL); + + g_signal_connect (WID (priv->builder, "hearing_sound_preferences_link"), + "activate-link", + G_CALLBACK (hearing_sound_preferences_clicked), self); +} + +/* typing/keyboard section */ + +static void +cc_ua_panel_init_keyboard (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* Typing assistant (on-screen keyboard) */ + w = WID (priv->builder, "typing_assistant_switch"); + g_settings_bind (priv->application_settings, "screen-keyboard-enabled", + w, "active", G_SETTINGS_BIND_DEFAULT); + + /* enable shortcuts */ + w = WID (priv->builder, "typing_keyboard_toggle_switch"); + g_settings_bind (priv->kb_settings, "enable", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* sticky keys */ + w = WID (priv->builder, "typing_sticky_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "stickykeys-enable", w, sticky_keys_section); + + w = WID (priv->builder, "typing_sticky_keys_disable_two_keys_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-two-key-off", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + w = WID (priv->builder, "typing_sticky_keys_beep_modifier_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-modifier-beep", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + /* slow keys */ + w = WID (priv->builder, "typing_slow_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "slowkeys-enable", w, slow_keys_section); + + w = WID (priv->builder, "typing_slowkeys_delay_scale"); + g_settings_bind (priv->kb_settings, "slowkeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_pressed_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-press", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_accepted_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-accept", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-reject", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* bounce keys */ + w = WID (priv->builder, "typing_bounce_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "bouncekeys-enable", w, bounce_keys_section); + + w = WID (priv->builder, "typing_bouncekeys_delay_scale"); + g_settings_bind (priv->kb_settings, "bouncekeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_bounce_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "bouncekeys-beep-reject", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); +} + +/* mouse/pointing & clicking section */ +static gboolean +pointing_mouse_preferences_clicked_cb (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "mouse", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_mouse (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* mouse keys */ + w = WID (priv->builder, "pointing_mouse_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "mousekeys-enable", w, NULL); + + /* simulated secondary click */ + w = WID (priv->builder, "pointing_second_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "secondary-click-enabled", w, secondary_click_section); + + w = WID (priv->builder, "pointing_secondary_click_delay_scale"); + g_settings_bind (priv->mouse_settings, "secondary-click-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* dwell click */ + w = WID (priv->builder, "pointing_hover_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "dwell-click-enabled", w, dwell_click_section); + + w = WID (priv->builder, "pointing_dwell_delay_scale"); + g_settings_bind (priv->mouse_settings, "dwell-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "pointing_dwell_threshold_scale"); + g_settings_bind (priv->mouse_settings, "dwell-threshold", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* mouse preferences button */ + g_signal_connect (WID (priv->builder, "pointing_mouse_preferences_link"), + "activate-link", + G_CALLBACK (pointing_mouse_preferences_clicked_cb), self); +} + +static void +cc_ua_panel_init (CcUaPanel *self) +{ + CcUaPanelPrivate *priv; + GtkWidget *widget; + GError *err = NULL; + gchar *objects[] = { "universal_access_box", "contrast_model", + "text_size_model", "slowkeys_delay_adjustment", + "bouncekeys_delay_adjustment", "click_delay_adjustment", + "dwell_time_adjustment", "dwell_threshold_adjustment", + "seeing_sizegroup", "typing_sizegroup", + "pointing_sizegroup", "pointing_sizegroup2", + "pointing_scale_sizegroup", "sizegroup1", + "hearing_sizegroup", + NULL }; + + priv = self->priv = UA_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_objects_from_file (priv->builder, + GNOMECC_UI_DIR "/uap.ui", + objects, + &err); + + if (err) + { + g_warning ("Could not load interface file: %s", err->message); + g_error_free (err); + + g_object_unref (priv->builder); + priv->builder = NULL; + + return; + } + + priv->interface_settings = g_settings_new ("org.gnome.desktop.interface"); + priv->wm_settings = g_settings_new ("org.gnome.desktop.wm.preferences"); + priv->kb_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard"); + priv->mouse_settings = g_settings_new ("org.gnome.desktop.a11y.mouse"); + priv->application_settings = g_settings_new ("org.gnome.desktop.a11y.applications"); + priv->mediakeys_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + + cc_ua_panel_init_keyboard (self); + cc_ua_panel_init_mouse (self); + cc_ua_panel_init_hearing (self); + cc_ua_panel_init_seeing (self); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, + "universal_access_box"); + + gtk_container_add (GTK_CONTAINER (self), widget); +} + +void +cc_ua_panel_register (GIOModule *module) +{ + cc_ua_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_UA_PANEL, + "universal-access", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-password-dialog.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-password-dialog.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-password-dialog.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-password-dialog.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,703 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "um-password-dialog.h" +#include "um-user-manager.h" +#include "um-utils.h" +#include "run-passwd.h" +#include "pw-utils.h" + +struct _UmPasswordDialog { + GtkWidget *dialog; + GtkWidget *user_icon; + GtkWidget *user_name; + GtkWidget *action_label; + GtkWidget *action_combo; + GtkWidget *password_entry; + GtkWidget *verify_entry; + GtkWidget *strength_indicator; + GtkWidget *strength_indicator_label; + GtkWidget *normal_hint_entry; + GtkWidget *normal_hint_label; + GtkWidget *show_password_button; + GtkWidget *ok_button; + + UmUser *user; + + GtkWidget *old_password_label; + GtkWidget *old_password_entry; + gboolean old_password_ok; + + PasswdHandler *passwd_handler; + + gchar **generated; + gint next_generated; +}; + +static void +generate_one_password (GtkWidget *widget, + UmPasswordDialog *um) +{ + gchar *pwd; + + pwd = pw_generate (); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), pwd); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + + g_free (pwd); +} + +static void +activate_icon (GtkEntry *entry, + GtkEntryIconPosition pos, + GdkEventButton *event, + UmPasswordDialog *um) +{ + generate_one_password (GTK_WIDGET (entry), um); +} + +static void +populate_menu (GtkEntry *entry, + GtkMenu *menu, + UmPasswordDialog *um) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_mnemonic (_("_Generate a password")); + g_signal_connect (item, "activate", + G_CALLBACK (generate_one_password), um); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); +} + +static void +finish_password_change (UmPasswordDialog *um) +{ + gtk_widget_hide (um->dialog); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), " "); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + + um_password_dialog_set_user (um, NULL); +} + +static void +cancel_password_dialog (GtkButton *button, + UmPasswordDialog *um) +{ + finish_password_change (um); +} + +static void +dialog_closed (GtkWidget *dialog, + gint response_id, + UmPasswordDialog *um) +{ + gtk_widget_destroy (dialog); +} + +static void +password_changed_cb (PasswdHandler *handler, + GError *error, + UmPasswordDialog *um) +{ + GtkWidget *dialog; + const gchar *primary_text; + const gchar *secondary_text; + + gtk_widget_set_sensitive (um->dialog, TRUE); + gdk_window_set_cursor (gtk_widget_get_window (um->dialog), NULL); + + if (!error) { + finish_password_change (um); + return; + } + + if (error->code == PASSWD_ERROR_REJECTED) { + primary_text = error->message; + secondary_text = _("Please choose another password."); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), ""); + gtk_widget_grab_focus (um->password_entry); + + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + } + else if (error->code == PASSWD_ERROR_AUTH_FAILED) { + primary_text = error->message; + secondary_text = _("Please type your current password again."); + + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + gtk_widget_grab_focus (um->old_password_entry); + } + else { + primary_text = _("Password could not be changed"); + secondary_text = error->message; + } + + dialog = gtk_message_dialog_new (GTK_WINDOW (um->dialog), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary_text); + g_signal_connect (dialog, "response", + G_CALLBACK (dialog_closed), um); + gtk_window_present (GTK_WINDOW (dialog)); + +} + +static void +accept_password_dialog (GtkButton *button, + UmPasswordDialog *um) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gint mode; + const gchar *hint; + const gchar *password; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo)); + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->action_combo), &iter); + gtk_tree_model_get (model, &iter, 1, &mode, -1); + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + hint = gtk_entry_get_text (GTK_ENTRY (um->normal_hint_entry)); + + if (mode == 0 && um_user_get_uid (um->user) == getuid ()) { + GdkDisplay *display; + GdkCursor *cursor; + + /* When setting a password for the current user, + * use passwd directly, to preserve the audit trail + * and to e.g. update the keyring password. + */ + passwd_change_password (um->passwd_handler, password, (PasswdCallback) password_changed_cb, um); + gtk_widget_set_sensitive (um->dialog, FALSE); + display = gtk_widget_get_display (um->dialog); + cursor = gdk_cursor_new_for_display (display, GDK_WATCH); + gdk_window_set_cursor (gtk_widget_get_window (um->dialog), cursor); + gdk_display_flush (display); + g_object_unref (cursor); + } + else { + um_user_set_password (um->user, mode, password, hint); + finish_password_change (um); + } +} + +static void +update_sensitivity (UmPasswordDialog *um) +{ + const gchar *password, *verify; + const gchar *old_password; + const gchar *tooltip; + gboolean can_change; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry)); + old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry)); + + if (strlen (password) < pw_min_length ()) { + can_change = FALSE; + if (password[0] == '\0') { + tooltip = _("You need to enter a new password"); + } + else { + tooltip = _("The new password is too short"); + } + } + else if (strcmp (password, verify) != 0) { + can_change = FALSE; + if (verify[0] == '\0') { + tooltip = _("You need to confirm the password"); + } + else { + tooltip = _("The passwords do not match"); + } + } + else if (!um->old_password_ok) { + can_change = FALSE; + if (old_password[0] == '\0') { + tooltip = _("You need to enter your current password"); + } + else { + tooltip = _("The current password is not correct"); + } + } + else { + can_change = TRUE; + tooltip = NULL; + } + + gtk_widget_set_sensitive (um->ok_button, can_change); + gtk_widget_set_tooltip_text (um->ok_button, tooltip); +} + +static void +action_changed (GtkComboBox *combo, + UmPasswordDialog *um) +{ + gint active; + + active = gtk_combo_box_get_active (combo); + if (active == 0) { + gtk_widget_set_sensitive (um->password_entry, TRUE); + gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, TRUE); + gtk_widget_set_sensitive (um->verify_entry, TRUE); + gtk_widget_set_sensitive (um->old_password_entry, TRUE); + gtk_widget_set_sensitive (um->normal_hint_entry, TRUE); + gtk_widget_set_sensitive (um->normal_hint_label, TRUE); + gtk_widget_set_sensitive (um->strength_indicator_label, TRUE); + gtk_widget_set_sensitive (um->show_password_button, TRUE); + + update_sensitivity (um); + } + else { + gtk_widget_set_sensitive (um->password_entry, FALSE); + gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, FALSE); + gtk_widget_set_sensitive (um->verify_entry, FALSE); + gtk_widget_set_sensitive (um->old_password_entry, FALSE); + gtk_widget_set_sensitive (um->normal_hint_entry, FALSE); + gtk_widget_set_sensitive (um->normal_hint_label, FALSE); + gtk_widget_set_sensitive (um->strength_indicator_label, FALSE); + gtk_widget_set_sensitive (um->show_password_button, FALSE); + gtk_widget_set_sensitive (um->ok_button, TRUE); + } +} + +static void +show_password_toggled (GtkToggleButton *button, + UmPasswordDialog *um) +{ + gboolean active; + + active = gtk_toggle_button_get_active (button); + gtk_entry_set_visibility (GTK_ENTRY (um->password_entry), active); + gtk_entry_set_visibility (GTK_ENTRY (um->verify_entry), active); +} + +static void +update_password_strength (UmPasswordDialog *um) +{ + const gchar *password; + const gchar *old_password; + const gchar *username; + gint strength_level; + const gchar *hint; + const gchar *long_hint; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry)); + username = um_user_get_user_name (um->user); + + pw_strength (password, old_password, username, + &hint, &long_hint, &strength_level); + + gtk_level_bar_set_value (GTK_LEVEL_BAR (um->strength_indicator), strength_level); + gtk_label_set_label (GTK_LABEL (um->strength_indicator_label), hint); + gtk_widget_set_tooltip_text (um->strength_indicator, long_hint); + gtk_widget_set_tooltip_text (um->strength_indicator_label, long_hint); +} + +static void +update_password_match (UmPasswordDialog *um) +{ + const char *password; + const char *verify; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry)); + + if (strlen (password) > 0 && strlen (verify) > 0) { + if (strcmp (password, verify) != 0) { + set_entry_validation_error (GTK_ENTRY (um->verify_entry), + _("Passwords do not match")); + } + else { + clear_entry_validation_error (GTK_ENTRY (um->verify_entry)); + } + } +} + +static void +password_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + update_password_strength (um); + update_sensitivity (um); + update_password_match (um); +} + +static gboolean +password_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + update_password_match (um); + return FALSE; +} + +static void +verify_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + clear_entry_validation_error (GTK_ENTRY (entry)); + update_password_strength (um); + update_sensitivity (um); +} + +static gboolean +verify_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + update_password_match (um); + return FALSE; +} + +static void +entry_size_changed (GtkWidget *entry, + GtkAllocation *allocation, + GtkWidget *label) +{ + gtk_widget_set_size_request (label, allocation->width, -1); +} + +static void +auth_cb (PasswdHandler *handler, + GError *error, + UmPasswordDialog *um) +{ + if (error) { + um->old_password_ok = FALSE; + set_entry_validation_error (GTK_ENTRY (um->old_password_entry), + _("Wrong password")); + } + else { + um->old_password_ok = TRUE; + clear_entry_validation_error (GTK_ENTRY (um->old_password_entry)); + } + + update_sensitivity (um); +} + +static gboolean +old_password_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + if (strlen (text) > 0) { + passwd_authenticate (um->passwd_handler, text, + (PasswdCallback)auth_cb, um); + } + + return FALSE; +} + +static void +old_password_entry_activate (GtkWidget *entry, + UmPasswordDialog *um) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + if (strlen (text) > 0) { + passwd_authenticate (um->passwd_handler, text, + (PasswdCallback)auth_cb, um); + } +} + + +static void +old_password_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + clear_entry_validation_error (GTK_ENTRY (entry)); + um->old_password_ok = FALSE; + update_sensitivity (um); +} + +void +um_password_dialog_set_privileged (UmPasswordDialog *um, + gboolean privileged) +{ + if (privileged) { + gtk_widget_set_visible (um->action_label, TRUE); + gtk_widget_set_visible (um->action_combo, TRUE); + } + else { + gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0); + gtk_widget_set_visible (um->action_label, FALSE); + gtk_widget_set_visible (um->action_combo, FALSE); + } +} + +UmPasswordDialog * +um_password_dialog_new (void) +{ + GtkBuilder *builder; + GError *error; + const gchar *filename; + UmPasswordDialog *um; + GtkWidget *widget; + const char *old_label; + char *label; + gint len; + + builder = gtk_builder_new (); + + error = NULL; + filename = UIDIR "/password-dialog.ui"; + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + filename = "data/password-dialog.ui"; + if (!gtk_builder_add_from_file (builder, filename, &error)) { + g_error ("%s", error->message); + g_error_free (error); + return NULL; + } + + um = g_new0 (UmPasswordDialog, 1); + + um->action_label = (GtkWidget *) gtk_builder_get_object (builder, "action-label"); + widget = (GtkWidget *) gtk_builder_get_object (builder, "action-combo"); + g_signal_connect (widget, "changed", + G_CALLBACK (action_changed), um); + um->action_combo = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog"); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + um->dialog = widget; + + um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon"); + um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name"); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button"); + g_signal_connect (widget, "clicked", + G_CALLBACK (cancel_password_dialog), um); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button"); + g_signal_connect (widget, "clicked", + G_CALLBACK (accept_password_dialog), um); + gtk_widget_grab_default (widget); + um->ok_button = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label"); + old_label = gtk_label_get_label (GTK_LABEL (widget)); + label = g_strdup_printf ("%s", + "help:gnome-help/user-goodpassword", + old_label); + gtk_label_set_markup (GTK_LABEL (widget), label); + g_free (label); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "show-password-checkbutton"); + g_signal_connect (widget, "toggled", + G_CALLBACK (show_password_toggled), um); + um->show_password_button = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "password-entry"); + g_signal_connect (widget, "notify::text", + G_CALLBACK (password_entry_changed), um); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (password_entry_focus_out), um); + gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); + + g_signal_connect (widget, "icon-press", + G_CALLBACK (activate_icon), um); + g_signal_connect (widget, "populate-popup", + G_CALLBACK (populate_menu), um); + + um->password_entry = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "old-password-entry"); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (old_password_entry_focus_out), um); + g_signal_connect (widget, "notify::text", + G_CALLBACK (old_password_entry_changed), um); + g_signal_connect (widget, "activate", + G_CALLBACK (old_password_entry_activate), um); + um->old_password_entry = widget; + um->old_password_label = (GtkWidget *) gtk_builder_get_object (builder, "old-password-label"); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "verify-entry"); + g_signal_connect (widget, "notify::text", + G_CALLBACK (verify_entry_changed), um); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (verify_entry_focus_out), um); + um->verify_entry = widget; + + len = 0; + len = MAX (len, strlen (C_("Password strength", "Too short"))); + len = MAX (len, strlen (C_("Password strength", "Weak"))); + len = MAX (len, strlen (C_("Password strength", "Fair"))); + len = MAX (len, strlen (C_("Password strength", "Good"))); + len = MAX (len, strlen (C_("Password strength", "Strong"))); + len += 2; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); + gtk_label_set_width_chars (GTK_LABEL (widget), len); + + um->normal_hint_entry = (GtkWidget *) gtk_builder_get_object (builder, "normal-hint-entry"); + + /* Label size hack. + * This only sort-of works because the dialog is non-resizable. + */ + widget = (GtkWidget *)gtk_builder_get_object (builder, "password-normal-hint-description-label"); + g_signal_connect (um->normal_hint_entry, "size-allocate", + G_CALLBACK (entry_size_changed), widget); + um->normal_hint_label = widget; + + um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator"); + + um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); + + g_object_unref (builder); + + return um; +} + +void +um_password_dialog_free (UmPasswordDialog *um) +{ + gtk_widget_destroy (um->dialog); + + if (um->user) + g_object_unref (um->user); + + if (um->passwd_handler) + passwd_destroy (um->passwd_handler); + + g_free (um); +} + +static gboolean +visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + UmPasswordDialog *um) +{ + if (um->user) { + gint mode; + gboolean locked = um_user_get_locked (um->user); + + gtk_tree_model_get (model, iter, 1, &mode, -1); + + if (mode == 3 && locked) + return FALSE; + + if (mode == 4 && !locked) + return FALSE; + + return TRUE; + } + + return TRUE; +} + +void +um_password_dialog_set_user (UmPasswordDialog *um, + UmUser *user) +{ + GdkPixbuf *pixbuf; + GtkTreeModel *model; + + if (um->user) { + g_object_unref (um->user); + um->user = NULL; + } + if (user) { + um->user = g_object_ref (user); + + pixbuf = um_user_render_icon (user, FALSE, 48); + gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf); + g_object_unref (pixbuf); + + gtk_label_set_label (GTK_LABEL (um->user_name), + um_user_get_real_name (user)); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), FALSE); + if (um_user_get_uid (um->user) == getuid () && + um_user_get_password_mode (um->user) == UM_PASSWORD_MODE_REGULAR) { + gtk_widget_show (um->old_password_label); + gtk_widget_show (um->old_password_entry); + um->old_password_ok = FALSE; + } + else { + gtk_widget_hide (um->old_password_label); + gtk_widget_hide (um->old_password_entry); + um->old_password_ok = TRUE; + } + if (um_user_get_uid (um->user) == getuid()) { + if (um->passwd_handler != NULL) + passwd_destroy (um->passwd_handler); + um->passwd_handler = passwd_init (); + } + } + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo)); + if (!GTK_IS_TREE_MODEL_FILTER (model)) { + model = gtk_tree_model_filter_new (model, NULL); + gtk_combo_box_set_model (GTK_COMBO_BOX (um->action_combo), model); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model), + (GtkTreeModelFilterVisibleFunc) visible_func, + um, NULL); + } + + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model)); + gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0); +} + +void +um_password_dialog_show (UmPasswordDialog *um, + GtkWindow *parent) +{ + gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent); + gtk_window_present (GTK_WINDOW (um->dialog)); + if (um->old_password_ok == FALSE) + gtk_widget_grab_focus (um->old_password_entry); + else + gtk_widget_grab_focus (um->password_entry); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-user-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-user-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-user-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/user-accounts/um-user-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1398 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include "um-user-panel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ + +#include "shell/cc-editable-entry.h" + +#include "um-user.h" +#include "um-user-manager.h" + +#include "um-editable-button.h" +#include "um-editable-combo.h" + +#include "um-account-dialog.h" +#include "cc-language-chooser.h" +#include "um-password-dialog.h" +#include "um-photo-dialog.h" +#include "um-fingerprint-dialog.h" +#include "um-utils.h" + +#include "cc-common-language.h" + +#define USER_ACCOUNTS_PERMISSION "org.gnome.controlcenter.user-accounts.administration" + +CC_PANEL_REGISTER (UmUserPanel, um_user_panel) + +#define UM_USER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), UM_TYPE_USER_PANEL, UmUserPanelPrivate)) + +struct _UmUserPanelPrivate { + UmUserManager *um; + GtkBuilder *builder; + + GtkWidget *main_box; + GPermission *permission; + GtkWidget *language_chooser; + + UmPasswordDialog *password_dialog; + UmPhotoDialog *photo_dialog; +}; + +static GtkWidget * +get_widget (UmUserPanelPrivate *d, const char *name) +{ + return (GtkWidget *)gtk_builder_get_object (d->builder, name); +} + +enum { + USER_COL, + FACE_COL, + NAME_COL, + USER_ROW_COL, + TITLE_COL, + HEADING_ROW_COL, + SORT_KEY_COL, + AUTOLOGIN_COL, + NUM_USER_LIST_COLS +}; + +static UmUser * +get_selected_user (UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *model; + UmUser *user; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + selection = gtk_tree_view_get_selection (tv); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, &user, -1); + return user; + } + + return NULL; +} + +static char * +get_name_col_str (UmUser *user) +{ + return g_markup_printf_escaped ("%s\n%s", + um_user_get_display_name (user), + um_user_get_user_name (user)); +} + +static void +user_added (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkWidget *widget; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeIter iter; + GtkTreeIter dummy; + GdkPixbuf *pixbuf; + gchar *text; + GtkTreeSelection *selection; + gint sort_key; + gboolean is_autologin; + + g_debug ("user added: %d %s\n", um_user_get_uid (user), um_user_get_real_name (user)); + widget = get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + store = GTK_LIST_STORE (model); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + + pixbuf = um_user_render_icon (user, TRUE, 48); + text = get_name_col_str (user); + + is_autologin = um_user_get_automatic_login (user); + + if (um_user_get_uid (user) == getuid ()) { + sort_key = 1; + } + else { + sort_key = 3; + } + gtk_list_store_append (store, &iter); + + gtk_list_store_set (store, &iter, + USER_COL, user, + FACE_COL, pixbuf, + NAME_COL, text, + USER_ROW_COL, TRUE, + TITLE_COL, NULL, + HEADING_ROW_COL, FALSE, + SORT_KEY_COL, sort_key, + AUTOLOGIN_COL, is_autologin, + -1); + g_object_unref (pixbuf); + g_free (text); + + if (sort_key == 1 && + !gtk_tree_selection_get_selected (selection, &model, &dummy)) { + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +get_previous_user_row (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *prev) +{ + GtkTreePath *path; + UmUser *user; + + path = gtk_tree_model_get_path (model, iter); + while (gtk_tree_path_prev (path)) { + gtk_tree_model_get_iter (model, prev, path); + gtk_tree_model_get (model, prev, USER_COL, &user, -1); + if (user) { + g_object_unref (user); + break; + } + } + gtk_tree_path_free (path); +} + +static gboolean +get_next_user_row (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *next) +{ + UmUser *user; + + *next = *iter; + while (gtk_tree_model_iter_next (model, next)) { + gtk_tree_model_get (model, next, USER_COL, &user, -1); + if (user) { + g_object_unref (user); + return TRUE; + } + } + + return FALSE; +} + +static void +user_removed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter, next; + UmUser *u; + + g_debug ("user removed: %s\n", um_user_get_user_name (user)); + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + selection = gtk_tree_view_get_selection (tv); + model = gtk_tree_view_get_model (tv); + store = GTK_LIST_STORE (model); + if (gtk_tree_model_get_iter_first (model, &iter)) { + do { + gtk_tree_model_get (model, &iter, USER_COL, &u, -1); + + if (u != NULL) { + if (um_user_get_uid (user) == um_user_get_uid (u)) { + if (!get_next_user_row (model, &iter, &next)) + get_previous_user_row (model, &iter, &next); + gtk_list_store_remove (store, &iter); + gtk_tree_selection_select_iter (selection, &next); + g_object_unref (u); + break; + } + g_object_unref (u); + } + } while (gtk_tree_model_iter_next (model, &iter)); + } +} + +static void show_user (UmUser *user, UmUserPanelPrivate *d); + +static void +user_changed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + UmUser *current; + GdkPixbuf *pixbuf; + char *text; + gboolean is_autologin; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (tv); + selection = gtk_tree_view_get_selection (tv); + + gtk_tree_model_get_iter_first (model, &iter); + do { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + if (current == user) { + pixbuf = um_user_render_icon (user, TRUE, 48); + text = get_name_col_str (user); + is_autologin = um_user_get_automatic_login (user); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + USER_COL, user, + FACE_COL, pixbuf, + NAME_COL, text, + AUTOLOGIN_COL, is_autologin, + -1); + g_object_unref (pixbuf); + g_free (text); + g_object_unref (current); + + break; + } + if (current) + g_object_unref (current); + + } while (gtk_tree_model_iter_next (model, &iter)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + + if (current == user) { + show_user (user, d); + } + if (current) + g_object_unref (current); + } +} + +static void +select_created_user (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + UmUserPanelPrivate *d = user_data; + UmAccountDialog *dialog; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + UmUser *current; + GtkTreePath *path; + UmUser *user; + + dialog = UM_ACCOUNT_DIALOG (object); + user = um_account_dialog_finish (dialog, result); + gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (user == NULL) + return; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (tv); + selection = gtk_tree_view_get_selection (tv); + + gtk_tree_model_get_iter_first (model, &iter); + do { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + if (user == current) { + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_scroll_to_cell (tv, path, NULL, FALSE, 0.0, 0.0); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + g_object_unref (current); + break; + } + if (current) + g_object_unref (current); + } while (gtk_tree_model_iter_next (model, &iter)); + + g_object_unref (user); +} + +static void +add_user (GtkButton *button, UmUserPanelPrivate *d) +{ + UmAccountDialog *dialog; + + dialog = um_account_dialog_new (); + um_account_dialog_show (dialog, GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + select_created_user, d); +} + +static void +delete_user_done (UmUserManager *manager, + GAsyncResult *res, + UmUserPanelPrivate *d) +{ + GError *error; + + error = NULL; + if (!um_user_manager_delete_user_finish (manager, res, &error)) { + if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Failed to delete user")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_signal_connect (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_present (GTK_WINDOW (dialog)); + } + g_error_free (error); + } +} + +static void +delete_user_response (GtkWidget *dialog, + gint response_id, + UmUserPanelPrivate *d) +{ + UmUser *user; + gboolean remove_files; + + gtk_widget_destroy (dialog); + + if (response_id == GTK_RESPONSE_CANCEL) { + return; + } + else if (response_id == GTK_RESPONSE_NO) { + remove_files = TRUE; + } + else { + remove_files = FALSE; + } + + user = get_selected_user (d); + + um_user_manager_delete_user (d->um, + user, + remove_files, + (GAsyncReadyCallback)delete_user_done, + d, + NULL); + + g_object_unref (user); +} + +static void +delete_user (GtkButton *button, UmUserPanelPrivate *d) +{ + UmUser *user; + GtkWidget *dialog; + + user = get_selected_user (d); + if (user == NULL) { + return; + } + else if (um_user_get_uid (user) == getuid ()) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("You cannot delete your own account.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + } + else if (um_user_is_logged_in (user)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("%s is still logged in"), + um_user_get_real_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Deleting a user while they are logged in can leave the system in an inconsistent state.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + } + else { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Do you want to keep %s's files?"), + um_user_get_real_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("It is possible to keep the home directory, mail spool and temporary files around when deleting a user account.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Delete Files"), GTK_RESPONSE_NO, + _("_Keep Files"), GTK_RESPONSE_YES, + _("_Cancel"), GTK_RESPONSE_CANCEL, + NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-users"); + + g_signal_connect (dialog, "response", + G_CALLBACK (delete_user_response), d); + } + + g_signal_connect (dialog, "close", + G_CALLBACK (gtk_widget_destroy), NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + gtk_window_present (GTK_WINDOW (dialog)); + + g_object_unref (user); +} + +static const gchar * +get_invisible_text (void) +{ + GtkWidget *entry; + gunichar invisible_char; + static gchar invisible_text[40]; + gchar *p; + gint i; + + entry = gtk_entry_new (); + invisible_char = gtk_entry_get_invisible_char (GTK_ENTRY (entry)); + if (invisible_char == 0) + invisible_char = 0x2022; + + g_object_ref_sink (entry); + g_object_unref (entry); + + /* five bullets */ + p = invisible_text; + for (i = 0; i < 5; i++) + p += g_unichar_to_utf8 (invisible_char, p); + *p = 0; + + return invisible_text; +} + +static const gchar * +get_password_mode_text (UmUser *user) +{ + const gchar *text; + + if (um_user_get_locked (user)) { + text = C_("Password mode", "Account disabled"); + } + else { + switch (um_user_get_password_mode (user)) { + case UM_PASSWORD_MODE_REGULAR: + text = get_invisible_text (); + break; + case UM_PASSWORD_MODE_SET_AT_LOGIN: + text = C_("Password mode", "To be set at next login"); + break; + case UM_PASSWORD_MODE_NONE: + text = C_("Password mode", "None"); + break; + default: + g_assert_not_reached (); + } + } + + return text; +} + +static void +autologin_changed (GObject *object, + GParamSpec *pspec, + UmUserPanelPrivate *d) +{ + gboolean active; + UmUser *user; + + active = gtk_switch_get_active (GTK_SWITCH (object)); + user = get_selected_user (d); + + if (active != um_user_get_automatic_login (user)) { + um_user_set_automatic_login (user, active); + if (um_user_get_automatic_login (user)) { + GSList *list; + GSList *l; + list = um_user_manager_list_users (d->um); + for (l = list; l != NULL; l = l->next) { + UmUser *u = l->data; + if (um_user_get_uid (u) != um_user_get_uid (user)) { + um_user_set_automatic_login (user, FALSE); + } + } + g_slist_free (list); + } + } + + g_object_unref (user); +} + +static void +show_user (UmUser *user, UmUserPanelPrivate *d) +{ + GtkWidget *image; + GtkWidget *label; + GtkWidget *label2; + GtkWidget *label3; + GdkPixbuf *pixbuf; + gchar *lang; + GtkWidget *widget; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean show, enable; + + pixbuf = um_user_render_icon (user, FALSE, 48); + image = get_widget (d, "user-icon-image"); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + image = get_widget (d, "user-icon-image2"); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + g_object_unref (pixbuf); + + um_photo_dialog_set_user (d->photo_dialog, user); + + widget = get_widget (d, "full-name-entry"); + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), um_user_get_real_name (user)); + gtk_widget_set_tooltip_text (widget, um_user_get_user_name (user)); + + widget = get_widget (d, "account-type-combo"); + um_editable_combo_set_active (UM_EDITABLE_COMBO (widget), um_user_get_account_type (user)); + + widget = get_widget (d, "account-password-button"); + um_editable_button_set_text (UM_EDITABLE_BUTTON (widget), get_password_mode_text (user)); + enable = um_user_is_local_account (user); + gtk_widget_set_sensitive (widget, enable); + + widget = get_widget (d, "autologin-switch"); + g_signal_handlers_block_by_func (widget, autologin_changed, d); + gtk_switch_set_active (GTK_SWITCH (widget), um_user_get_automatic_login (user)); + g_signal_handlers_unblock_by_func (widget, autologin_changed, d); + + if (um_user_get_locked (user)) + gtk_widget_set_sensitive (widget, FALSE); + + widget = get_widget (d, "account-language-combo"); + model = um_editable_combo_get_model (UM_EDITABLE_COMBO (widget)); + cc_add_user_languages (model); + + lang = g_strdup (um_user_get_language (user)); + if (!lang) + lang = cc_common_language_get_current_language (); + cc_common_language_get_iter_for_language (model, lang, &iter); + um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (widget), &iter); + g_free (lang); + + /* Fingerprint: show when self, possible, and local account */ + widget = get_widget (d, "account-fingerprint-notebook"); + label = get_widget (d, "account-fingerprint-label"); + label2 = get_widget (d, "account-fingerprint-value-label"); + label3 = get_widget (d, "account-fingerprint-button-label"); + show = (um_user_get_uid (user) == getuid() && + um_user_is_local_account (user) && + set_fingerprint_label (label2, label3)); + gtk_widget_set_visible (label, show); + gtk_widget_set_visible (widget, show); + + /* Autologin: show when local account */ + widget = get_widget (d, "autologin-switch"); + label = get_widget (d, "autologin-label"); + show = um_user_is_local_account (user); + gtk_widget_set_visible (widget, show); + gtk_widget_set_visible (label, show); +} + +static void on_permission_changed (GPermission *permission, GParamSpec *pspec, gpointer data); + +static void +selected_user_changed (GtkTreeSelection *selection, UmUserPanelPrivate *d) +{ + GtkTreeModel *model; + GtkTreeIter iter; + UmUser *user; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, &user, -1); + show_user (user, d); + if (d->permission != NULL) + on_permission_changed (d->permission, NULL, d); + gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), TRUE); + g_object_unref (user); + } else { + gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), FALSE); + } +} + +static void +change_name_done (GtkWidget *entry, + UmUserPanelPrivate *d) +{ + const gchar *text; + UmUser *user; + + user = get_selected_user (d); + + text = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry)); + if (g_strcmp0 (text, um_user_get_real_name (user)) != 0) { + um_user_set_real_name (user, text); + } + + g_object_unref (user); +} + +static void +account_type_changed (UmEditableCombo *combo, + UmUserPanelPrivate *d) +{ + UmUser *user; + GtkTreeModel *model; + GtkTreeIter iter; + gint account_type; + + user = get_selected_user (d); + + model = um_editable_combo_get_model (combo); + um_editable_combo_get_active_iter (combo, &iter); + gtk_tree_model_get (model, &iter, 1, &account_type, -1); + + if (account_type != um_user_get_account_type (user)) { + um_user_set_account_type (user, account_type); + } + + g_object_unref (user); +} + +static void +language_response (GtkDialog *dialog, + gint response_id, + UmUserPanelPrivate *d) +{ + GtkWidget *combo; + UmUser *user; + gchar *lang; + GtkTreeModel *model; + GtkTreeIter iter; + + user = get_selected_user (d); + + combo = get_widget (d, "account-language-combo"); + model = um_editable_combo_get_model (UM_EDITABLE_COMBO (combo)); + + if (response_id == GTK_RESPONSE_OK) { + lang = cc_language_chooser_get_language (GTK_WIDGET (dialog)); + um_user_set_language (user, lang); + } + else { + lang = g_strdup (um_user_get_language (user)); + if (!lang) + lang = cc_common_language_get_current_language (); + } + cc_common_language_get_iter_for_language (model, lang, &iter); + um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (combo), &iter); + g_free (lang); + + gtk_widget_hide (GTK_WIDGET (dialog)); + gtk_widget_set_sensitive (combo, TRUE); + + g_object_unref (user); +} + +static void +language_changed (UmEditableCombo *combo, + UmUserPanelPrivate *d) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *lang; + UmUser *user; + + if (!um_editable_combo_get_active_iter (combo, &iter)) + return; + + user = get_selected_user (d); + + model = um_editable_combo_get_model (combo); + + gtk_tree_model_get (model, &iter, 0, &lang, -1); + if (lang) { + if (g_strcmp0 (lang, um_user_get_language (user)) != 0) { + um_user_set_language (user, lang); + } + g_free (lang); + goto out; + } + + if (d->language_chooser) { + cc_language_chooser_clear_filter (d->language_chooser); + gtk_window_present (GTK_WINDOW (d->language_chooser)); + gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE); + goto out; + } + + d->language_chooser = cc_language_chooser_new (gtk_widget_get_toplevel (d->main_box), FALSE); + + g_signal_connect (d->language_chooser, "response", + G_CALLBACK (language_response), d); + g_signal_connect (d->language_chooser, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + gdk_window_set_cursor (gtk_widget_get_window (gtk_widget_get_toplevel (d->main_box)), NULL); + gtk_window_present (GTK_WINDOW (d->language_chooser)); + gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE); + +out: + g_object_unref (user); +} + +static void +change_password (GtkButton *button, UmUserPanelPrivate *d) +{ + UmUser *user; + + user = get_selected_user (d); + + um_password_dialog_set_user (d->password_dialog, user); + um_password_dialog_show (d->password_dialog, + GTK_WINDOW (gtk_widget_get_toplevel (d->main_box))); + + g_object_unref (user); +} + +static void +change_fingerprint (GtkButton *button, UmUserPanelPrivate *d) +{ + GtkWidget *label, *label2; + UmUser *user; + + user = get_selected_user (d); + + g_assert (g_strcmp0 (g_get_user_name (), um_user_get_user_name (user)) == 0); + + label = get_widget (d, "account-fingerprint-value-label"); + label2 = get_widget (d, "account-fingerprint-button-label"); + fingerprint_button_clicked (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), label, label2, user); + + g_object_unref (user); +} + +static gint +sort_users (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) +{ + UmUser *ua, *ub; + gint sa, sb; + gint result; + + gtk_tree_model_get (model, a, USER_COL, &ua, SORT_KEY_COL, &sa, -1); + gtk_tree_model_get (model, b, USER_COL, &ub, SORT_KEY_COL, &sb, -1); + + if (sa < sb) { + result = -1; + } + else if (sa > sb) { + result = 1; + } + else { + result = um_user_collate (ua, ub); + } + + if (ua) { + g_object_unref (ua); + } + if (ub) { + g_object_unref (ub); + } + + return result; +} + +static gboolean +dont_select_headings (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean selected, + gpointer data) +{ + GtkTreeIter iter; + gboolean is_user; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, USER_ROW_COL, &is_user, -1); + + return is_user; +} + +static void +users_loaded (UmUserManager *manager, + UmUserPanelPrivate *d) +{ + GSList *list, *l; + UmUser *user; + GtkWidget *dialog; + + if (um_user_manager_no_service (d->um)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + GTK_DIALOG_MODAL, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_CLOSE, + _("Failed to contact the accounts service")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Please make sure that the AccountService is installed and enabled.")); + g_signal_connect_swapped (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + gtk_widget_show (dialog); + + gtk_widget_set_sensitive (d->main_box, FALSE); + } + + list = um_user_manager_list_users (d->um); + g_debug ("Got %d users\n", g_slist_length (list)); + + g_signal_connect (d->um, "user-changed", G_CALLBACK (user_changed), d); + + for (l = list; l; l = l->next) { + user = l->data; + g_debug ("adding user %s\n", um_user_get_real_name (user)); + user_added (d->um, user, d); + } + g_slist_free (list); + + g_signal_connect (d->um, "user-added", G_CALLBACK (user_added), d); + g_signal_connect (d->um, "user-removed", G_CALLBACK (user_removed), d); +} + +static void +add_unlock_tooltip (GtkWidget *button) +{ + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + /* Translator comments: + * We split the line in 2 here to "make it look good", as there's + * no good way to do this in GTK+ for tooltips. See: + * https://bugzilla.gnome.org/show_bug.cgi?id=657168 */ + setup_tooltip_with_embedded_icon (button, + _("To make changes,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + g_signal_connect (button, "button-release-event", + G_CALLBACK (show_tooltip_now), NULL); +} + +static void +remove_unlock_tooltip (GtkWidget *button) +{ + setup_tooltip_with_embedded_icon (button, NULL, NULL, NULL); + g_signal_handlers_disconnect_by_func (button, + G_CALLBACK (show_tooltip_now), NULL); +} + +static void +on_permission_changed (GPermission *permission, + GParamSpec *pspec, + gpointer data) +{ + UmUserPanelPrivate *d = data; + gboolean is_authorized; + gboolean self_selected; + UmUser *user; + GtkWidget *widget; + + user = get_selected_user (d); + if (!user) { + return; + } + + is_authorized = g_permission_get_allowed (G_PERMISSION (d->permission)); + self_selected = um_user_get_uid (user) == geteuid (); + + widget = get_widget (d, "add-user-toolbutton"); + gtk_widget_set_sensitive (widget, is_authorized); + if (is_authorized) { + setup_tooltip_with_embedded_icon (widget, _("Create a user account"), NULL, NULL); + } + else { + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + setup_tooltip_with_embedded_icon (widget, + _("To create a user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + } + + widget = get_widget (d, "remove-user-toolbutton"); + gtk_widget_set_sensitive (widget, is_authorized && !self_selected); + if (is_authorized) { + setup_tooltip_with_embedded_icon (widget, _("Delete the selected user account"), NULL, NULL); + } + else { + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + + setup_tooltip_with_embedded_icon (widget, + _("To delete the selected user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + } + + if (!um_user_is_local_account (user)) { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), FALSE); + remove_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), FALSE); + remove_unlock_tooltip (get_widget (d, "autologin-switch")); + + } else if (is_authorized && um_user_is_local_account (user)) { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), TRUE); + remove_unlock_tooltip (get_widget (d, "autologin-switch")); + } + else { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), FALSE); + add_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), FALSE); + add_unlock_tooltip (get_widget (d, "autologin-switch")); + } + + /* The full name entry: insensitive if remote or not authorized and not self */ + widget = get_widget (d, "full-name-entry"); + if (!um_user_is_local_account (user)) { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), FALSE); + remove_unlock_tooltip (widget); + + } else if (is_authorized || self_selected) { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), TRUE); + remove_unlock_tooltip (widget); + + } else { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), FALSE); + add_unlock_tooltip (widget); + } + + if (is_authorized || self_selected) { + gtk_widget_show (get_widget (d, "user-icon-button")); + gtk_widget_hide (get_widget (d, "user-icon-nonbutton")); + + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-language-combo")); + + um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-password-button")); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 1); + } + else { + gtk_widget_hide (get_widget (d, "user-icon-button")); + gtk_widget_show (get_widget (d, "user-icon-nonbutton")); + + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), FALSE); + add_unlock_tooltip (get_widget (d, "account-language-combo")); + + um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), FALSE); + add_unlock_tooltip (get_widget (d, "account-password-button")); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 0); + } + + um_password_dialog_set_privileged (d->password_dialog, is_authorized); + + g_object_unref (user); +} + +static gboolean +match_user (GtkTreeModel *model, + gint column, + const gchar *key, + GtkTreeIter *iter, + gpointer search_data) +{ + UmUser *user; + const gchar *name; + gchar *normalized_key = NULL; + gchar *normalized_name = NULL; + gchar *case_normalized_key = NULL; + gchar *case_normalized_name = NULL; + gchar *p; + gboolean result = TRUE; + gint i; + + gtk_tree_model_get (model, iter, USER_COL, &user, -1); + + if (!user) { + goto out; + } + + normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); + if (!normalized_key) { + goto out; + } + + case_normalized_key = g_utf8_casefold (normalized_key, -1); + + for (i = 0; i < 2; i++) { + if (i == 0) { + name = um_user_get_real_name (user); + } + else { + name = um_user_get_user_name (user); + } + g_free (normalized_name); + normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL); + if (normalized_name) { + g_free (case_normalized_name); + case_normalized_name = g_utf8_casefold (normalized_name, -1); + p = strstr (case_normalized_name, case_normalized_key); + + /* poor man's \b */ + if (p == case_normalized_name || (p && p[-1] == ' ')) { + result = FALSE; + break; + } + } + } + + out: + if (user) { + g_object_unref (user); + } + g_free (normalized_key); + g_free (case_normalized_key); + g_free (normalized_name); + g_free (case_normalized_name); + + return result; +} + +static void +autologin_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + UmUserPanelPrivate *d) +{ + gboolean is_autologin; + + gtk_tree_model_get (model, iter, AUTOLOGIN_COL, &is_autologin, -1); + + if (is_autologin) { + g_object_set (cell, "icon-name", "emblem-default-symbolic", NULL); + } else { + g_object_set (cell, "icon-name", NULL, NULL); + } +} + +static void +setup_main_window (UmUserPanelPrivate *d) +{ + GtkWidget *userlist; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkTreeSelection *selection; + GtkWidget *button; + GtkTreeIter iter; + gint expander_size; + gchar *title; + GIcon *icon; + GError *error = NULL; + gchar *names[3]; + + userlist = get_widget (d, "list-treeview"); + store = gtk_list_store_new (NUM_USER_LIST_COLS, + UM_TYPE_USER, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_INT, + G_TYPE_BOOLEAN); + model = (GtkTreeModel *)store; + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), sort_users, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (userlist), model); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (userlist), USER_COL); + gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (userlist), + match_user, NULL, NULL); + g_object_unref (model); + + g_signal_connect (d->um, "users-loaded", G_CALLBACK (users_loaded), d); + + gtk_widget_style_get (userlist, "expander-size", &expander_size, NULL); + gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (userlist), - (expander_size + 6)); + + title = g_strdup_printf ("%s", _("My Account")); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + TITLE_COL, title, + HEADING_ROW_COL, TRUE, + SORT_KEY_COL, 0, + AUTOLOGIN_COL, FALSE, + -1); + g_free (title); + + title = g_strdup_printf ("%s", _("Other Accounts")); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + TITLE_COL, title, + HEADING_ROW_COL, TRUE, + SORT_KEY_COL, 2, + AUTOLOGIN_COL, FALSE, + -1); + g_free (title); + + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "pixbuf", FACE_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", NAME_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", TITLE_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", HEADING_ROW_COL); + cell = gtk_cell_renderer_pixbuf_new (); + g_object_set (cell, "follow-state", TRUE, NULL); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + gtk_tree_view_column_set_cell_data_func (column, + cell, + (GtkTreeCellDataFunc) autologin_cell_data_func, + d, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (userlist), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (userlist)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (selection, "changed", G_CALLBACK (selected_user_changed), d); + gtk_tree_selection_set_select_function (selection, dont_select_headings, NULL, NULL); + + gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (get_widget (d, "list-scrolledwindow")), 300); + gtk_widget_set_size_request (get_widget (d, "list-scrolledwindow"), 200, -1); + + button = get_widget (d, "add-user-toolbutton"); + g_signal_connect (button, "clicked", G_CALLBACK (add_user), d); + + button = get_widget (d, "remove-user-toolbutton"); + g_signal_connect (button, "clicked", G_CALLBACK (delete_user), d); + + button = get_widget (d, "user-icon-nonbutton"); + add_unlock_tooltip (button); + + button = get_widget (d, "full-name-entry"); + g_signal_connect (button, "editing-done", G_CALLBACK (change_name_done), d); + + button = get_widget (d, "account-type-combo"); + g_signal_connect (button, "editing-done", G_CALLBACK (account_type_changed), d); + + button = get_widget (d, "account-password-button"); + g_signal_connect (button, "start-editing", G_CALLBACK (change_password), d); + + button = get_widget (d, "account-language-combo"); + g_signal_connect (button, "editing-done", G_CALLBACK (language_changed), d); + + button = get_widget (d, "autologin-switch"); + g_signal_connect (button, "notify::active", G_CALLBACK (autologin_changed), d); + + button = get_widget (d, "account-fingerprint-button"); + g_signal_connect (button, "clicked", + G_CALLBACK (change_fingerprint), d); + + d->permission = (GPermission *)polkit_permission_new_sync (USER_ACCOUNTS_PERMISSION, NULL, NULL, &error); + if (d->permission != NULL) { + g_signal_connect (d->permission, "notify", + G_CALLBACK (on_permission_changed), d); + on_permission_changed (d->permission, NULL, d); + } else { + g_warning ("Cannot create '%s' permission: %s", USER_ACCOUNTS_PERMISSION, error->message); + g_error_free (error); + } + + button = get_widget (d, "add-user-toolbutton"); + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + setup_tooltip_with_embedded_icon (button, + _("To create a user account,\nclick the * icon first"), + "*", + icon); + button = get_widget (d, "remove-user-toolbutton"); + setup_tooltip_with_embedded_icon (button, + _("To delete the selected user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); +} + +static void +um_user_panel_init (UmUserPanel *self) +{ + UmUserPanelPrivate *d; + GError *error; + volatile GType type G_GNUC_UNUSED; + const gchar *filename; + GtkWidget *button; + GtkStyleContext *context; + + d = self->priv = UM_USER_PANEL_PRIVATE (self); + + /* register types that the builder might need */ + type = um_editable_button_get_type (); + type = cc_editable_entry_get_type (); + type = um_editable_combo_get_type (); + + gtk_widget_set_size_request (GTK_WIDGET (self), -1, 350); + + d->builder = gtk_builder_new (); + d->um = um_user_manager_ref_default (); + + filename = UIDIR "/user-accounts-dialog.ui"; + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + filename = "data/user-accounts-dialog.ui"; + } + error = NULL; + if (!gtk_builder_add_from_file (d->builder, filename, &error)) { + g_error ("%s", error->message); + g_error_free (error); + return; + } + + setup_main_window (d); + d->password_dialog = um_password_dialog_new (); + button = get_widget (d, "user-icon-button"); + d->photo_dialog = um_photo_dialog_new (button); + d->main_box = get_widget (d, "accounts-vbox"); + gtk_widget_reparent (d->main_box, GTK_WIDGET (self)); + + context = gtk_widget_get_style_context (get_widget (d, "list-scrolledwindow")); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + context = gtk_widget_get_style_context (get_widget (d, "add-remove-toolbar")); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); +} + +static void +um_user_panel_dispose (GObject *object) +{ + UmUserPanelPrivate *priv = UM_USER_PANEL (object)->priv; + + if (priv->um) { + g_object_unref (priv->um); + priv->um = NULL; + } + if (priv->builder) { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->password_dialog) { + um_password_dialog_free (priv->password_dialog); + priv->password_dialog = NULL; + } + if (priv->photo_dialog) { + um_photo_dialog_free (priv->photo_dialog); + priv->photo_dialog = NULL; + } + if (priv->language_chooser) { + gtk_widget_destroy (priv->language_chooser); + priv->language_chooser = NULL; + } + if (priv->permission) { + g_object_unref (priv->permission); + priv->permission = NULL; + } + G_OBJECT_CLASS (um_user_panel_parent_class)->dispose (object); +} + +static GPermission * +um_user_panel_get_permission (CcPanel *panel) +{ + UmUserPanelPrivate *priv = UM_USER_PANEL (panel)->priv; + + return priv->permission; +} + +static const char * +um_user_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/user-accounts"; +} + +static void +um_user_panel_class_init (UmUserPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + object_class->dispose = um_user_panel_dispose; + + panel_class->get_permission = um_user_panel_get_permission; + panel_class->get_help_uri = um_user_panel_get_help_uri; + + g_type_class_add_private (klass, sizeof (UmUserPanelPrivate)); +} + +void +um_user_panel_register (GIOModule *module) +{ + um_user_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + UM_TYPE_USER_PANEL, "user-accounts", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/wacom/cc-wacom-panel.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/wacom/cc-wacom-panel.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/wacom/cc-wacom-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/panels/wacom/cc-wacom-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,401 @@ +/* + * Copyright © 2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Peter Hutterer + * Bastien Nocera + * + */ + +#include + +#include +#include + +#include "cc-wacom-panel.h" +#include "cc-wacom-page.h" +#include "gsd-wacom-device.h" + +#define WID(x) (GtkWidget *) gtk_builder_get_object (priv->builder, x) + +CC_PANEL_REGISTER (CcWacomPanel, cc_wacom_panel) + +#define WACOM_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_WACOM_PANEL, CcWacomPanelPrivate)) + +struct _CcWacomPanelPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GHashTable *devices; /* key=GdkDevice, value=GsdWacomDevice */ + GHashTable *pages; /* key=device name, value=GtkWidget */ + GdkDeviceManager *manager; + guint device_added_id; + guint device_removed_id; +}; + +typedef struct { + const char *name; + GsdWacomDevice *stylus; + GsdWacomDevice *eraser; + GsdWacomDevice *pad; +} Tablet; + +enum { + WACOM_PAGE = -1, + PLUG_IN_PAGE = 0, +}; + +/* Boilerplate code goes below */ + +static void +cc_wacom_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_wacom_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_wacom_panel_dispose (GObject *object) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL (object)->priv; + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->manager) + { + g_signal_handler_disconnect (priv->manager, priv->device_added_id); + g_signal_handler_disconnect (priv->manager, priv->device_removed_id); + priv->manager = NULL; + } + + if (priv->devices) + { + g_hash_table_destroy (priv->devices); + priv->devices = NULL; + } + + if (priv->pages) + { + g_hash_table_destroy (priv->pages); + priv->pages = NULL; + } + + G_OBJECT_CLASS (cc_wacom_panel_parent_class)->dispose (object); +} + +static const char * +cc_wacom_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/wacom"; +} + +static void +cc_wacom_panel_class_init (CcWacomPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcWacomPanelPrivate)); + + object_class->get_property = cc_wacom_panel_get_property; + object_class->set_property = cc_wacom_panel_set_property; + object_class->dispose = cc_wacom_panel_dispose; + + panel_class->get_help_uri = cc_wacom_panel_get_help_uri; +} + +static void +remove_page (GtkNotebook *notebook, + GtkWidget *widget) +{ + int num_pages, i; + + num_pages = gtk_notebook_get_n_pages (notebook); + g_return_if_fail (num_pages > 1); + for (i = 1; i < num_pages; i++) { + if (gtk_notebook_get_nth_page (notebook, i) == widget) { + gtk_notebook_remove_page (notebook, i); + return; + } + } +} + +static void +update_current_page (CcWacomPanel *self) +{ + GHashTable *ht; + GList *devices, *tablets, *l; + gboolean changed; + CcWacomPanelPrivate *priv; + + priv = self->priv; + changed = FALSE; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + devices = g_hash_table_get_values (priv->devices); + for (l = devices; l; l = l->next) { + Tablet *tablet; + GsdWacomDevice *device; + + device = l->data; + tablet = g_hash_table_lookup (ht, gsd_wacom_device_get_name (device)); + if (tablet == NULL) { + tablet = g_new0 (Tablet, 1); + tablet->name = gsd_wacom_device_get_name (device); + g_hash_table_insert (ht, (gpointer) tablet->name, tablet); + } + + switch (gsd_wacom_device_get_device_type (device)) { + case WACOM_TYPE_STYLUS: + tablet->stylus = device; + break; + case WACOM_TYPE_ERASER: + tablet->eraser = device; + break; + case WACOM_TYPE_PAD: + tablet->pad = device; + break; + default: + /* Nothing */ + ; + } + } + g_list_free (devices); + + /* We now have a list of Tablet structs, + * see which ones are full tablets */ + tablets = g_hash_table_get_values (ht); + for (l = tablets; l; l = l->next) { + Tablet *tablet; + GtkWidget *page; + + tablet = l->data; + if (tablet->stylus == NULL || + tablet->eraser == NULL) { + page = g_hash_table_lookup (priv->pages, tablet->name); + if (page != NULL) { + remove_page (GTK_NOTEBOOK (priv->notebook), page); + g_hash_table_remove (priv->pages, tablet->name); + + changed = TRUE; + } + continue; + } + /* this code is called once the stylus + eraser were set up, but the pad does not exist yet */ + page = g_hash_table_lookup (priv->pages, tablet->name); + if (page == NULL) { + page = cc_wacom_page_new (self, tablet->stylus, tablet->eraser, tablet->pad); + cc_wacom_page_set_navigation (CC_WACOM_PAGE (page), GTK_NOTEBOOK (priv->notebook), TRUE); + gtk_widget_show (page); + gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page, NULL); + g_hash_table_insert (priv->pages, g_strdup (tablet->name), page); + + changed = TRUE; + } else { + cc_wacom_page_update_tools (CC_WACOM_PAGE (page), tablet->stylus, tablet->eraser, tablet->pad); + } + } + g_list_free (tablets); + + g_hash_table_destroy (ht); + + if (changed == TRUE) { + int num_pages; + + num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)); + if (num_pages > 1) + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), WACOM_PAGE); + } +} + +static void +add_known_device (CcWacomPanel *self, + GdkDevice *gdk_device) +{ + CcWacomPanelPrivate *priv; + GsdWacomDevice *device; + + priv = self->priv; + + device = gsd_wacom_device_new (gdk_device); + if (gsd_wacom_device_get_device_type (device) == WACOM_TYPE_INVALID) { + g_object_unref (device); + return; + } + g_debug ("Adding device '%s' (type: '%s') to known devices list", + gsd_wacom_device_get_tool_name (device), + gsd_wacom_device_type_to_string (gsd_wacom_device_get_device_type (device))); + g_hash_table_insert (priv->devices, (gpointer) gdk_device, device); +} + +static void +device_removed_cb (GdkDeviceManager *manager, + GdkDevice *gdk_device, + CcWacomPanel *self) +{ + g_hash_table_remove (self->priv->devices, gdk_device); + update_current_page (self); +} + +static void +device_added_cb (GdkDeviceManager *manager, + GdkDevice *device, + CcWacomPanel *self) +{ + add_known_device (self, device); + update_current_page (self); +} + +static gboolean +link_activated (GtkLinkButton *button, + CcWacomPanel *self) +{ + cc_wacom_panel_switch_to_panel (self, "bluetooth"); + return TRUE; +} + +void +cc_wacom_panel_switch_to_panel (CcWacomPanel *self, + const char *panel) +{ + CcShell *shell; + GError *error = NULL; + + g_return_if_fail (self); + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, panel, NULL, &error) == FALSE) + { + g_warning ("Failed to activate '%s' panel: %s", panel, error->message); + g_error_free (error); + } +} + +static void +enbiggen_label (GtkLabel *label) +{ + const char *str; + char *new_str; + + str = gtk_label_get_text (label); + new_str = g_strdup_printf ("%s", str); + gtk_label_set_markup (label, new_str); + g_free (new_str); +} + +static void +cc_wacom_panel_init (CcWacomPanel *self) +{ + CcWacomPanelPrivate *priv; + GtkNotebook *notebook; + GtkWidget *widget; + GList *devices, *l; + GError *error = NULL; + char *objects[] = { + "main-box", + NULL + }; + + priv = self->priv = WACOM_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_objects_from_file (priv->builder, + GNOMECC_UI_DIR "/gnome-wacom-properties.ui", + objects, + &error); + if (error != NULL) + { + g_warning ("Error loading UI file: %s", error->message); + g_object_unref (priv->builder); + g_error_free (error); + return; + } + + /* Notebook */ + notebook = GTK_NOTEBOOK (gtk_notebook_new ()); + priv->notebook = GTK_WIDGET (notebook); + + gtk_notebook_set_show_tabs (notebook, FALSE); + gtk_widget_set_vexpand (GTK_WIDGET (notebook), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (notebook), 0); + g_object_set (G_OBJECT (notebook), + "margin-top", 0, + "margin-right", 24, + "margin-left", 24, + "margin-bottom", 24, + NULL); + + gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (notebook)); + gtk_widget_show (priv->notebook); + + /* No tablets page */ + widget = WID ("main-box"); + enbiggen_label (GTK_LABEL (WID ("advice-label1"))); + gtk_notebook_append_page (notebook, widget, NULL); + + g_signal_connect (G_OBJECT (WID ("linkbutton")), "activate-link", + G_CALLBACK (link_activated), self); + + priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + priv->pages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + priv->manager = gdk_display_get_device_manager (gdk_display_get_default ()); + priv->device_added_id = g_signal_connect (G_OBJECT (priv->manager), "device-added", + G_CALLBACK (device_added_cb), self); + priv->device_removed_id = g_signal_connect (G_OBJECT (priv->manager), "device-removed", + G_CALLBACK (device_removed_cb), self); + + devices = gdk_device_manager_list_devices (priv->manager, GDK_DEVICE_TYPE_SLAVE); + for (l = devices; l ; l = l->next) + add_known_device (self, l->data); + g_list_free (devices); + + update_current_page (self); +} + +void +cc_wacom_panel_register (GIOModule *module) +{ + cc_wacom_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_WACOM_PANEL, "wacom", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/shell/control-center.c gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/shell/control-center.c --- gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/shell/control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/53_use_ubuntu_help.patch/shell/control-center.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + +#include "config.h" + +#include +#include + +#include "gnome-control-center.h" + +#include +#include +#include + +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "cc-shell-log.h" + +G_GNUC_NORETURN static gboolean +option_version_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + g_print ("%s %s\n", PACKAGE, VERSION); + exit (0); +} + +static char **start_panels = NULL; +static gboolean show_overview = FALSE; +static gboolean verbose = FALSE; +static gboolean show_help = FALSE; +static gboolean show_help_gtk = FALSE; +static gboolean show_help_all = FALSE; + +const GOptionEntry all_options[] = { + { "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_version_cb, NULL, NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, N_("Enable verbose mode"), NULL }, + { "overview", 'o', 0, G_OPTION_ARG_NONE, &show_overview, N_("Show the overview"), NULL }, + { "help", 'h', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &show_help, N_("Show help options"), NULL }, + { "help-all", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &show_help_all, N_("Show help options"), NULL }, + { "help-gtk", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &show_help_gtk, N_("Show help options"), NULL }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &start_panels, N_("Panel to display"), NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } /* end the list */ +}; + +static int +application_command_line_cb (GApplication *application, + GApplicationCommandLine *command_line, + GnomeControlCenter *shell) +{ + int argc; + char **argv; + int retval = 0; + GOptionContext *context; + GError *error = NULL; + + verbose = FALSE; + show_overview = FALSE; + show_help = FALSE; + start_panels = NULL; + + argv = g_application_command_line_get_arguments (command_line, &argc); + + context = g_option_context_new (N_("- System Settings")); + g_option_context_add_main_entries (context, all_options, GETTEXT_PACKAGE); + g_option_context_set_translation_domain(context, GETTEXT_PACKAGE); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_set_help_enabled (context, FALSE); + + if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) + { + g_print (_("%s\nRun '%s --help' to see a full list of available command line options.\n"), + error->message, argv[0]); + g_error_free (error); + g_option_context_free (context); + return 1; + } + + if (show_help || show_help_all || show_help_gtk) + { + gchar *help; + GOptionGroup *group; + + if (show_help || show_help_all) + group = NULL; + else + group = gtk_get_option_group (FALSE); + + help = g_option_context_get_help (context, FALSE, group); + g_print ("%s", help); + g_free (help); + g_option_context_free (context); + return 0; + } + + g_option_context_free (context); + + cc_shell_log_set_debug (verbose); + + gnome_control_center_show (shell, GTK_APPLICATION (application)); + + if (show_overview) + { + gnome_control_center_set_overview_page (shell); + } + else if (start_panels != NULL && start_panels[0] != NULL) + { + const char *start_id; + GError *err = NULL; + + start_id = start_panels[0]; + + if (start_panels[1]) + g_debug ("Extra argument: %s", start_panels[1]); + else + g_debug ("No extra argument"); + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), start_id, (const gchar**)start_panels+1, &err)) + { + g_warning ("Could not load setting panel \"%s\": %s", start_id, + (err) ? err->message : "Unknown error"); + retval = 1; + if (err) + { + g_error_free (err); + err = NULL; + } + } + } + + gnome_control_center_present (shell); + gdk_notify_startup_complete (); + + g_strfreev (argv); + if (start_panels != NULL) + { + g_strfreev (start_panels); + start_panels = NULL; + } + show_overview = FALSE; + + return retval; +} + +static void +help_activated (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GnomeControlCenter *shell = user_data; + CcPanel *panel = cc_shell_get_active_panel (CC_SHELL (shell)); + GtkWidget *window = cc_shell_get_toplevel (CC_SHELL (shell)); + const char *uri = NULL; + + if (panel) + uri = cc_panel_get_help_uri (panel); + + gtk_show_uri (gtk_widget_get_screen (window), + uri ? uri : "help:gnome-help/prefs", + GDK_CURRENT_TIME, NULL); +} + +static void +quit_activated (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GnomeControlCenter *shell = user_data; + g_object_unref (shell); +} + +static void +application_startup_cb (GApplication *application, + GnomeControlCenter *shell) +{ + GMenu *menu, *section; + GAction *action; + + action = G_ACTION (g_simple_action_new ("help", NULL)); + g_action_map_add_action (G_ACTION_MAP (application), action); + g_signal_connect (action, "activate", G_CALLBACK (help_activated), shell); + + action = G_ACTION (g_simple_action_new ("quit", NULL)); + g_action_map_add_action (G_ACTION_MAP (application), action); + g_signal_connect (action, "activate", G_CALLBACK (quit_activated), shell); + + menu = g_menu_new (); + + section = g_menu_new (); + g_menu_append (section, _("Help"), "app.help"); + g_menu_append (section, _("Quit"), "app.quit"); + + g_menu_append_section (menu, NULL, G_MENU_MODEL (section)); + + gtk_application_set_app_menu (GTK_APPLICATION (application), + G_MENU_MODEL (menu)); + + gtk_application_add_accelerator (GTK_APPLICATION (application), + "F1", "app.help", NULL); + + /* nothing else to do here, we don't want to show a window before + * we've looked at the commandline + */ +} + +int +main (int argc, char **argv) +{ + GnomeControlCenter *shell; + GtkApplication *application; + int status; + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + +#ifdef GDK_WINDOWING_X11 + XInitThreads (); +#endif + + gtk_init (&argc, &argv); + cc_shell_log_init (); + + /* register a symbolic icon size for use in sidebar lists */ + gtk_icon_size_register ("cc-sidebar-list", 24, 24); + + notify_init ("gnome-control-center"); + + shell = gnome_control_center_new (); + + /* enforce single instance of this application */ + application = gtk_application_new ("org.gnome.ControlCenter", G_APPLICATION_HANDLES_COMMAND_LINE); + g_signal_connect (application, "startup", + G_CALLBACK (application_startup_cb), shell); + g_signal_connect (application, "command-line", + G_CALLBACK (application_command_line_cb), shell); + + status = g_application_run (G_APPLICATION (application), argc, argv); + + g_object_unref (application); + + return status; +} diff -Nru gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/cc-keyboard-item.c gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/cc-keyboard-item.c --- gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/cc-keyboard-item.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/cc-keyboard-item.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,475 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include "cc-keyboard-item.h" + +#define CC_KEYBOARD_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_KEYBOARD_ITEM, CcKeyboardItemPrivate)) + +#define CUSTOM_KEYS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys.custom-keybinding" + +struct CcKeyboardItemPrivate +{ + /* properties */ + int foo; + + /* internal */ +}; + +enum { + PROP_0, + PROP_DESCRIPTION, + PROP_BINDING, + PROP_EDITABLE, + PROP_TYPE, + PROP_COMMAND +}; + +static void cc_keyboard_item_class_init (CcKeyboardItemClass *klass); +static void cc_keyboard_item_init (CcKeyboardItem *keyboard_item); +static void cc_keyboard_item_finalize (GObject *object); + +G_DEFINE_TYPE (CcKeyboardItem, cc_keyboard_item, G_TYPE_OBJECT) + +static gboolean +binding_from_string (const char *str, + guint *accelerator_key, + guint *keycode, + GdkModifierType *accelerator_mods) +{ + g_return_val_if_fail (accelerator_key != NULL, FALSE); + guint *keycodes; + + if (str == NULL || strcmp (str, "disabled") == 0) + { + *accelerator_key = 0; + *keycode = 0; + *accelerator_mods = 0; + return TRUE; + } + + gtk_accelerator_parse_with_keycode (str, accelerator_key, &keycodes, accelerator_mods); + + if (keycode != NULL) + *keycode = (keycodes ? keycodes[0] : 0); + g_free (keycodes); + + if (*accelerator_key == 0) + return FALSE; + else + return TRUE; +} + +static void +_set_description (CcKeyboardItem *item, + const char *value) +{ + g_free (item->description); + item->description = g_strdup (value); +} + +const char * +cc_keyboard_item_get_description (CcKeyboardItem *item) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_ITEM (item), NULL); + + return item->description; +} + +/* wrapper around g_settings_set_str[ing|v] */ +static void +settings_set_binding (GSettings *settings, + const char *key, + const char *value) +{ + GVariant *variant; + + variant = g_settings_get_value (settings, key); + + if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) + g_settings_set_string (settings, key, value); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING_ARRAY)) + { + char **str_array; + + str_array = g_variant_dup_strv (variant, NULL); + + /* create a space for the new binding if empty */ + if (*str_array == NULL) + { + g_free (str_array); + str_array = g_new0 (char *, 2); + } + + /* replace the first binding */ + g_free (*str_array); + *str_array = g_strdup (value); + + g_settings_set_strv (settings, key, (const char * const *)str_array); + g_strfreev (str_array); + } + + g_variant_unref (variant); +} + + +static void +_set_binding (CcKeyboardItem *item, + const char *value, + gboolean set_backend) +{ + g_free (item->binding); + item->binding = g_strdup (value); + binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); + + if (set_backend == FALSE) + return; + + settings_set_binding (item->settings, item->key, item->binding); +} + +const char * +cc_keyboard_item_get_binding (CcKeyboardItem *item) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_ITEM (item), NULL); + + return item->binding; +} + +static void +_set_type (CcKeyboardItem *item, + gint value) +{ + item->type = value; +} + +static void +_set_command (CcKeyboardItem *item, + const char *value) +{ + g_free (item->command); + item->command = g_strdup (value); +} + +const char * +cc_keyboard_item_get_command (CcKeyboardItem *item) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_ITEM (item), NULL); + + return item->command; +} + +static void +cc_keyboard_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CcKeyboardItem *self; + + self = CC_KEYBOARD_ITEM (object); + + switch (prop_id) { + case PROP_DESCRIPTION: + _set_description (self, g_value_get_string (value)); + break; + case PROP_BINDING: + _set_binding (self, g_value_get_string (value), TRUE); + break; + case PROP_COMMAND: + _set_command (self, g_value_get_string (value)); + break; + case PROP_TYPE: + _set_type (self, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_keyboard_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CcKeyboardItem *self; + + self = CC_KEYBOARD_ITEM (object); + + switch (prop_id) { + case PROP_DESCRIPTION: + g_value_set_string (value, self->description); + break; + case PROP_BINDING: + g_value_set_string (value, self->binding); + break; + case PROP_EDITABLE: + g_value_set_boolean (value, self->editable); + break; + case PROP_COMMAND: + g_value_set_string (value, self->command); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +cc_keyboard_item_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + CcKeyboardItem *keyboard_item; + + keyboard_item = CC_KEYBOARD_ITEM (G_OBJECT_CLASS (cc_keyboard_item_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (keyboard_item); +} + +static void +cc_keyboard_item_class_init (CcKeyboardItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = cc_keyboard_item_get_property; + object_class->set_property = cc_keyboard_item_set_property; + object_class->constructor = cc_keyboard_item_constructor; + object_class->finalize = cc_keyboard_item_finalize; + + g_object_class_install_property (object_class, + PROP_DESCRIPTION, + g_param_spec_string ("description", + "description", + "description", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_BINDING, + g_param_spec_string ("binding", + "binding", + "binding", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_EDITABLE, + g_param_spec_boolean ("editable", + NULL, + NULL, + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_TYPE, + g_param_spec_int ("type", + NULL, + NULL, + CC_KEYBOARD_ITEM_TYPE_NONE, + CC_KEYBOARD_ITEM_TYPE_GSETTINGS, + CC_KEYBOARD_ITEM_TYPE_NONE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, + PROP_COMMAND, + g_param_spec_string ("command", + "command", + "command", + NULL, + G_PARAM_READWRITE)); + + g_type_class_add_private (klass, sizeof (CcKeyboardItemPrivate)); +} + +static void +cc_keyboard_item_init (CcKeyboardItem *item) +{ + item->priv = CC_KEYBOARD_ITEM_GET_PRIVATE (item); +} + +static void +cc_keyboard_item_finalize (GObject *object) +{ + CcKeyboardItem *item; + + g_return_if_fail (object != NULL); + g_return_if_fail (CC_IS_KEYBOARD_ITEM (object)); + + item = CC_KEYBOARD_ITEM (object); + + g_return_if_fail (item->priv != NULL); + + if (item->settings != NULL) + g_object_unref (item->settings); + + /* Free memory */ + g_free (item->binding); + g_free (item->gettext_package); + g_free (item->gsettings_path); + g_free (item->description); + g_free (item->command); + g_free (item->schema); + g_free (item->key); + + G_OBJECT_CLASS (cc_keyboard_item_parent_class)->finalize (object); +} + +CcKeyboardItem * +cc_keyboard_item_new (CcKeyboardItemType type) +{ + GObject *object; + + object = g_object_new (CC_TYPE_KEYBOARD_ITEM, + "type", type, + NULL); + + return CC_KEYBOARD_ITEM (object); +} + +/* wrapper around g_settings_get_str[ing|v] */ +static char * +settings_get_binding (GSettings *settings, + const char *key) +{ + GVariant *variant; + char *value = NULL; + + variant = g_settings_get_value (settings, key); + if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) + value = g_variant_dup_string (variant, NULL); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING_ARRAY)) + { + const char **str_array; + + str_array = g_variant_get_strv (variant, NULL); + value = g_strdup (str_array[0]); + } + g_variant_unref (variant); + + return value; +} + +static void +binding_changed (GSettings *settings, + const char *key, + CcKeyboardItem *item) +{ + char *value; + + value = settings_get_binding (item->settings, item->key); + item->editable = g_settings_is_writable (item->settings, item->key); + _set_binding (item, value, FALSE); + g_free (value); + g_object_notify (G_OBJECT (item), "binding"); +} + +gboolean +cc_keyboard_item_load_from_gsettings_path (CcKeyboardItem *item, + const char *path, + gboolean reset) +{ + item->schema = g_strdup (CUSTOM_KEYS_SCHEMA); + item->gsettings_path = g_strdup (path); + item->key = g_strdup ("binding"); + item->settings = g_settings_new_with_path (item->schema, path); + item->editable = g_settings_is_writable (item->settings, item->key); + item->desc_editable = g_settings_is_writable (item->settings, "name"); + item->cmd_editable = g_settings_is_writable (item->settings, "command"); + + if (reset) + { + g_settings_reset (item->settings, "name"); + g_settings_reset (item->settings, "command"); + g_settings_reset (item->settings, "binding"); + } + + g_settings_bind (item->settings, "name", + G_OBJECT (item), "description", G_SETTINGS_BIND_DEFAULT); + g_settings_bind (item->settings, "command", + G_OBJECT (item), "command", G_SETTINGS_BIND_DEFAULT); + + item->binding = settings_get_binding (item->settings, item->key); + binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); + g_signal_connect (G_OBJECT (item->settings), "changed::binding", + G_CALLBACK (binding_changed), item); + + return TRUE; +} + +gboolean +cc_keyboard_item_load_from_gsettings (CcKeyboardItem *item, + const char *description, + const char *schema, + const char *key) +{ + char *signal_name; + + item->schema = g_strdup (schema); + item->key = g_strdup (key); + item->description = g_strdup (description); + + item->settings = g_settings_new (item->schema); + item->binding = settings_get_binding (item->settings, item->key); + item->editable = g_settings_is_writable (item->settings, item->key); + binding_from_string (item->binding, &item->keyval, &item->keycode, &item->mask); + + signal_name = g_strdup_printf ("changed::%s", item->key); + g_signal_connect (G_OBJECT (item->settings), signal_name, + G_CALLBACK (binding_changed), item); + g_free (signal_name); + + return TRUE; +} + +gboolean +cc_keyboard_item_equal (CcKeyboardItem *a, + CcKeyboardItem *b) +{ + if (a->type != b->type) + return FALSE; + switch (a->type) + { + case CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH: + return g_str_equal (a->gsettings_path, b->gsettings_path); + case CC_KEYBOARD_ITEM_TYPE_GSETTINGS: + return (g_str_equal (a->schema, b->schema) && + g_str_equal (a->key, b->key)); + default: + g_assert_not_reached (); + } + +} + +/* + * vim: sw=2 ts=8 cindent noai bs=2 + */ diff -Nru gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/keyboard-shortcuts.c gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/keyboard-shortcuts.c --- gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/keyboard-shortcuts.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/54_enable_alt_tap_in_shortcut.patch/panels/keyboard/keyboard-shortcuts.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1886 @@ +/* + * Copyright (C) 2010 Intel, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Thomas Wood + * Rodrigo Moya + */ + +#include + +#include + +#include "keyboard-shortcuts.h" +#include "cc-keyboard-item.h" +#include "cc-keyboard-option.h" +#include "wm-common.h" + +#define BINDINGS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys" +#define CUSTOM_KEYS_BASENAME "/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings" +#define CUSTOM_SHORTCUTS_ID "custom" +#define WID(builder, name) (GTK_WIDGET (gtk_builder_get_object (builder, name))) + +typedef struct { + /* The untranslated name, combine with ->package to translate */ + char *name; + /* The group of keybindings (system or application) */ + char *group; + /* The gettext package to use to translate the section title */ + char *package; + /* Name of the window manager the keys would apply to */ + char *wm_name; + /* The GSettings schema for the whole file, if any */ + char *schema; + /* an array of KeyListEntry */ + GArray *entries; +} KeyList; + +typedef struct +{ + CcKeyboardItemType type; + char *schema; /* GSettings schema name, if any */ + char *description; /* description for GSettings types */ + char *gettext_package; + char *name; /* GSettings schema path, or GSettings key name depending on type */ +} KeyListEntry; + +typedef enum +{ + SHORTCUT_TYPE_KEY_ENTRY, + SHORTCUT_TYPE_XKB_OPTION, +} ShortcutType; + +enum +{ + DETAIL_DESCRIPTION_COLUMN, + DETAIL_KEYENTRY_COLUMN, + DETAIL_TYPE_COLUMN, + DETAIL_N_COLUMNS +}; + +enum +{ + SECTION_DESCRIPTION_COLUMN, + SECTION_ID_COLUMN, + SECTION_GROUP_COLUMN, + SECTION_N_COLUMNS +}; + +static GSettings *binding_settings = NULL; +static GtkWidget *custom_shortcut_dialog = NULL; +static GtkWidget *custom_shortcut_name_entry = NULL; +static GtkWidget *custom_shortcut_command_entry = NULL; +static GHashTable *kb_system_sections = NULL; +static GHashTable *kb_apps_sections = NULL; +static GHashTable *kb_user_sections = NULL; + +static void +free_key_array (GPtrArray *keys) +{ + if (keys != NULL) + { + gint i; + + for (i = 0; i < keys->len; i++) + { + CcKeyboardItem *item; + + item = g_ptr_array_index (keys, i); + + g_object_unref (item); + } + + g_ptr_array_free (keys, TRUE); + } +} + +static GHashTable * +get_hash_for_group (BindingGroupType group) +{ + GHashTable *hash; + + switch (group) + { + case BINDING_GROUP_SYSTEM: + hash = kb_system_sections; + break; + case BINDING_GROUP_APPS: + hash = kb_apps_sections; + break; + case BINDING_GROUP_USER: + hash = kb_user_sections; + break; + default: + hash = NULL; + } + return hash; +} + +static gboolean +have_key_for_group (int group, const gchar *name) +{ + GHashTableIter iter; + GPtrArray *keys; + gint i; + + g_hash_table_iter_init (&iter, get_hash_for_group (group)); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&keys)) + { + for (i = 0; i < keys->len; i++) + { + CcKeyboardItem *item = g_ptr_array_index (keys, i); + + if (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS && + g_strcmp0 (name, item->key) == 0) + { + return TRUE; + } + + return FALSE; + } + } + + return FALSE; +} + +static gboolean +keybinding_key_changed_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + CcKeyboardItem *item) +{ + CcKeyboardItem *tmp_item; + + gtk_tree_model_get (item->model, iter, + DETAIL_KEYENTRY_COLUMN, &tmp_item, + -1); + + if (item == tmp_item) + { + gtk_tree_model_row_changed (item->model, path, iter); + return TRUE; + } + return FALSE; +} + +static void +item_changed (CcKeyboardItem *item, + GParamSpec *pspec, + gpointer user_data) +{ + /* update the model */ + gtk_tree_model_foreach (item->model, (GtkTreeModelForeachFunc) keybinding_key_changed_foreach, item); +} + + +static void +append_section (GtkBuilder *builder, + const gchar *title, + const gchar *id, + BindingGroupType group, + const KeyListEntry *keys_list) +{ + GPtrArray *keys_array; + GtkTreeModel *sort_model; + GtkTreeModel *model, *shortcut_model; + GtkTreeIter iter; + gint i; + GHashTable *hash; + gboolean is_new; + + hash = get_hash_for_group (group); + if (!hash) + return; + + sort_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview"))); + model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model)); + + shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview"))); + + /* Add all CcKeyboardItems for this section */ + is_new = FALSE; + keys_array = g_hash_table_lookup (hash, id); + if (keys_array == NULL) + { + keys_array = g_ptr_array_new (); + is_new = TRUE; + } + + for (i = 0; keys_list != NULL && keys_list[i].name != NULL; i++) + { + CcKeyboardItem *item; + gboolean ret; + + if (have_key_for_group (group, keys_list[i].name)) + continue; + + item = cc_keyboard_item_new (keys_list[i].type); + switch (keys_list[i].type) + { + case CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH: + ret = cc_keyboard_item_load_from_gsettings_path (item, keys_list[i].name, FALSE); + break; + case CC_KEYBOARD_ITEM_TYPE_GSETTINGS: + ret = cc_keyboard_item_load_from_gsettings (item, + keys_list[i].description, + keys_list[i].schema, + keys_list[i].name); + break; + default: + g_assert_not_reached (); + } + + if (ret == FALSE) + { + /* We don't actually want to popup a dialog - just skip this one */ + g_object_unref (item); + continue; + } + + item->model = shortcut_model; + item->group = group; + + g_signal_connect (G_OBJECT (item), "notify", + G_CALLBACK (item_changed), NULL); + + g_ptr_array_add (keys_array, item); + } + + /* Add the keys to the hash table */ + if (is_new) + { + g_hash_table_insert (hash, g_strdup (id), keys_array); + + /* Append the section to the left tree view */ + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + SECTION_DESCRIPTION_COLUMN, title, + SECTION_ID_COLUMN, id, + SECTION_GROUP_COLUMN, group, + -1); + } +} + +static void +parse_start_tag (GMarkupParseContext *ctx, + const gchar *element_name, + const gchar **attr_names, + const gchar **attr_values, + gpointer user_data, + GError **error) +{ + KeyList *keylist = (KeyList *) user_data; + KeyListEntry key; + const char *name, *schema, *description, *package; + + name = NULL; + schema = NULL; + package = NULL; + + /* The top-level element, names the section in the tree */ + if (g_str_equal (element_name, "KeyListEntries")) + { + const char *wm_name = NULL; + const char *group = NULL; + + while (*attr_names && *attr_values) + { + if (g_str_equal (*attr_names, "name")) + { + if (**attr_values) + name = *attr_values; + } else if (g_str_equal (*attr_names, "group")) { + if (**attr_values) + group = *attr_values; + } else if (g_str_equal (*attr_names, "wm_name")) { + if (**attr_values) + wm_name = *attr_values; + } else if (g_str_equal (*attr_names, "schema")) { + if (**attr_values) + schema = *attr_values; + } else if (g_str_equal (*attr_names, "package")) { + if (**attr_values) + package = *attr_values; + } + ++attr_names; + ++attr_values; + } + + if (name) + { + if (keylist->name) + g_warning ("Duplicate section name"); + g_free (keylist->name); + keylist->name = g_strdup (name); + } + if (wm_name) + { + if (keylist->wm_name) + g_warning ("Duplicate window manager name"); + g_free (keylist->wm_name); + keylist->wm_name = g_strdup (wm_name); + } + if (package) + { + if (keylist->package) + g_warning ("Duplicate gettext package name"); + g_free (keylist->package); + keylist->package = g_strdup (package); + bind_textdomain_codeset (keylist->package, "UTF-8"); + } + if (group) + { + if (keylist->group) + g_warning ("Duplicate group"); + g_free (keylist->group); + keylist->group = g_strdup (group); + } + if (schema) + { + if (keylist->schema) + g_warning ("Duplicate schema"); + g_free (keylist->schema); + keylist->schema = g_strdup (schema); + } + return; + } + + if (!g_str_equal (element_name, "KeyListEntry") + || attr_names == NULL + || attr_values == NULL) + return; + + schema = NULL; + description = NULL; + + while (*attr_names && *attr_values) + { + if (g_str_equal (*attr_names, "name")) + { + /* skip if empty */ + if (**attr_values) + name = *attr_values; + } else if (g_str_equal (*attr_names, "schema")) { + if (**attr_values) { + schema = *attr_values; + } + } else if (g_str_equal (*attr_names, "description")) { + if (**attr_values) { + if (keylist->package) + { + description = dgettext (keylist->package, *attr_values); + } + else + { + description = _(*attr_values); + } + } + } + + ++attr_names; + ++attr_values; + } + + if (name == NULL) + return; + + if (schema == NULL && + keylist->schema == NULL) { + g_debug ("Ignored GConf keyboard shortcut '%s'", name); + return; + } + + key.name = g_strdup (name); + key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS; + key.description = g_strdup (description); + key.gettext_package = g_strdup (keylist->package); + key.schema = schema ? g_strdup (schema) : g_strdup (keylist->schema); + g_array_append_val (keylist->entries, key); +} + +static gboolean +strv_contains (char **strv, + char *str) +{ + char **p = strv; + for (p = strv; *p; p++) + if (strcmp (*p, str) == 0) + return TRUE; + + return FALSE; +} + +static void +append_sections_from_file (GtkBuilder *builder, const gchar *path, const char *datadir, gchar **wm_keybindings) +{ + GError *err = NULL; + char *buf; + gsize buf_len; + KeyList *keylist; + KeyListEntry key, *keys; + const char *title; + int group; + guint i; + GMarkupParseContext *ctx; + GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL }; + + /* Parse file */ + if (!g_file_get_contents (path, &buf, &buf_len, &err)) + return; + + keylist = g_new0 (KeyList, 1); + keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry)); + ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL); + + if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) + { + g_warning ("Failed to parse '%s': '%s'", path, err->message); + g_error_free (err); + g_free (keylist->name); + g_free (keylist->package); + g_free (keylist->wm_name); + for (i = 0; i < keylist->entries->len; i++) + g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name); + g_array_free (keylist->entries, TRUE); + g_free (keylist); + keylist = NULL; + } + g_markup_parse_context_free (ctx); + g_free (buf); + + if (keylist == NULL) + return; + + /* If there's no keys to add, or the settings apply to a window manager + * that's not the one we're running */ + if (keylist->entries->len == 0 + || (keylist->wm_name != NULL && !strv_contains (wm_keybindings, keylist->wm_name)) + || keylist->name == NULL) + { + g_free (keylist->name); + g_free (keylist->package); + g_free (keylist->wm_name); + g_array_free (keylist->entries, TRUE); + g_free (keylist); + return; + } + + /* Empty KeyListEntry to end the array */ + key.name = NULL; + g_array_append_val (keylist->entries, key); + + keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE); + if (keylist->package) + { + char *localedir; + + localedir = g_build_filename (datadir, "locale", NULL); + bindtextdomain (keylist->package, localedir); + g_free (localedir); + + title = dgettext (keylist->package, keylist->name); + } else { + title = _(keylist->name); + } + if (keylist->group && strcmp (keylist->group, "system") == 0) + group = BINDING_GROUP_SYSTEM; + else + group = BINDING_GROUP_APPS; + + append_section (builder, title, keylist->name, group, keys); + + g_free (keylist->name); + g_free (keylist->package); + g_free (keylist->wm_name); + g_free (keylist->schema); + g_free (keylist->group); + + for (i = 0; keys[i].name != NULL; i++) { + KeyListEntry *entry = &keys[i]; + g_free (entry->schema); + g_free (entry->description); + g_free (entry->gettext_package); + g_free (entry->name); + } + + g_free (keylist); +} + +static void +append_sections_from_gsettings (GtkBuilder *builder) +{ + char **custom_paths; + GArray *entries; + KeyListEntry key; + int i; + + /* load custom shortcuts from GSettings */ + entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry)); + + custom_paths = g_settings_get_strv (binding_settings, "custom-keybindings"); + for (i = 0; custom_paths[i]; i++) + { + key.name = g_strdup (custom_paths[i]); + if (!have_key_for_group (BINDING_GROUP_USER, key.name)) + { + key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH; + g_array_append_val (entries, key); + } + else + g_free (key.name); + } + g_strfreev (custom_paths); + + if (entries->len > 0) + { + KeyListEntry *keys; + int i; + + /* Empty KeyListEntry to end the array */ + key.name = NULL; + g_array_append_val (entries, key); + + keys = (KeyListEntry *) entries->data; + append_section (builder, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, keys); + for (i = 0; i < entries->len; ++i) + { + g_free (keys[i].name); + } + } + else + { + append_section (builder, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, NULL); + } + + g_array_free (entries, TRUE); +} + +static void +reload_sections (CcPanel *panel) +{ + GtkBuilder *builder; + gchar **wm_keybindings; + GDir *dir; + GtkTreeModel *sort_model; + GtkTreeModel *section_model; + GtkTreeModel *shortcut_model; + const gchar * const * data_dirs; + guint i; + GtkTreeView *section_treeview; + GtkTreeSelection *selection; + GtkTreeIter iter; + GHashTable *loaded_files; + const char *section_to_set; + + builder = g_object_get_data (G_OBJECT (panel), "builder"); + + section_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview")); + sort_model = gtk_tree_view_get_model (section_treeview); + section_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model)); + + shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview"))); + /* FIXME: get current selection and keep it after refreshing */ + + /* Clear previous models and hash tables */ + gtk_list_store_clear (GTK_LIST_STORE (section_model)); + gtk_list_store_clear (GTK_LIST_STORE (shortcut_model)); + if (kb_system_sections != NULL) + g_hash_table_destroy (kb_system_sections); + kb_system_sections = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) free_key_array); + + if (kb_apps_sections != NULL) + g_hash_table_destroy (kb_apps_sections); + kb_apps_sections = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) free_key_array); + + if (kb_user_sections != NULL) + g_hash_table_destroy (kb_user_sections); + kb_user_sections = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) free_key_array); + + /* Load WM keybindings */ + wm_keybindings = wm_common_get_current_keybindings (); + + loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + data_dirs = g_get_system_data_dirs (); + for (i = 0; data_dirs[i] != NULL; i++) + { + char *dir_path; + const gchar *name; + + dir_path = g_build_filename (data_dirs[i], "gnome-control-center", "keybindings", NULL); + + dir = g_dir_open (dir_path, 0, NULL); + if (!dir) + { + g_free (dir_path); + continue; + } + + for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir)) + { + gchar *path; + + if (g_str_has_suffix (name, ".xml") == FALSE) + continue; + + if (g_hash_table_lookup (loaded_files, name) != NULL) + { + g_debug ("Not loading %s, it was already loaded from another directory", name); + continue; + } + + g_hash_table_insert (loaded_files, g_strdup (name), GINT_TO_POINTER (1)); + path = g_build_filename (dir_path, name, NULL); + append_sections_from_file (builder, path, data_dirs[i], wm_keybindings); + g_free (path); + } + g_free (dir_path); + g_dir_close (dir); + } + + g_hash_table_destroy (loaded_files); + g_strfreev (wm_keybindings); + + /* Add a separator */ + gtk_list_store_append (GTK_LIST_STORE (section_model), &iter); + gtk_list_store_set (GTK_LIST_STORE (section_model), &iter, + SECTION_DESCRIPTION_COLUMN, NULL, + SECTION_GROUP_COLUMN, BINDING_GROUP_SEPARATOR, + -1); + + /* Load custom keybindings */ + append_sections_from_gsettings (builder); + + /* Select the first item, or the requested section, if any */ + section_to_set = g_object_get_data (G_OBJECT (panel), "section-to-set"); + if (section_to_set != NULL) + { + if (keyboard_shortcuts_set_section (panel, section_to_set)) + { + g_object_set_data (G_OBJECT (panel), "section-to-set", NULL); + return; + } + } + gtk_tree_model_get_iter_first (sort_model, &iter); + selection = gtk_tree_view_get_selection (section_treeview); + gtk_tree_selection_select_iter (selection, &iter); + + g_object_set_data (G_OBJECT (panel), "section-to-set", NULL); +} + +static void +accel_set_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gpointer entry; + ShortcutType type; + + gtk_tree_model_get (model, iter, + DETAIL_KEYENTRY_COLUMN, &entry, + DETAIL_TYPE_COLUMN, &type, + -1); + + gtk_cell_renderer_set_visible (cell, FALSE); + + if (type == SHORTCUT_TYPE_XKB_OPTION && + GTK_IS_CELL_RENDERER_COMBO (cell)) + { + CcKeyboardOption *option = entry; + + gtk_cell_renderer_set_visible (cell, TRUE); + g_object_set (cell, + "model", cc_keyboard_option_get_store (option), + "text", cc_keyboard_option_get_current_value_description (option), + NULL); + } + else if (type == SHORTCUT_TYPE_KEY_ENTRY && + GTK_IS_CELL_RENDERER_TEXT (cell) && + !GTK_IS_CELL_RENDERER_COMBO (cell) && + entry != NULL) + { + CcKeyboardItem *item = entry; + + gtk_cell_renderer_set_visible (cell, TRUE); + + if (item->editable) + g_object_set (cell, + "editable", TRUE, + "accel-key", item->keyval, + "accel-mods", item->mask, + "keycode", item->keycode, + "style", PANGO_STYLE_NORMAL, + NULL); + else + g_object_set (cell, + "editable", FALSE, + "accel-key", item->keyval, + "accel-mods", item->mask, + "keycode", item->keycode, + "style", PANGO_STYLE_ITALIC, + NULL); + } +} + +static void +description_set_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *description; + CcKeyboardItem *item; + ShortcutType type; + + gtk_tree_model_get (model, iter, + DETAIL_DESCRIPTION_COLUMN, &description, + DETAIL_KEYENTRY_COLUMN, &item, + DETAIL_TYPE_COLUMN, &type, + -1); + + if (type == SHORTCUT_TYPE_XKB_OPTION) + { + g_object_set (cell, "text", description, NULL); + } + else + { + if (item != NULL) + g_object_set (cell, + "editable", FALSE, + "text", item->description != NULL ? + item->description : _(""), + NULL); + else + g_object_set (cell, + "editable", FALSE, NULL); + } + + g_free (description); +} + +static void +shortcut_selection_changed (GtkTreeSelection *selection, gpointer data) +{ + GtkWidget *button = data; + GtkTreeModel *model; + GtkTreeIter iter; + CcKeyboardItem *item; + gboolean can_remove; + ShortcutType type; + + can_remove = FALSE; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + DETAIL_KEYENTRY_COLUMN, &item, + DETAIL_TYPE_COLUMN, &type, + -1); + if (type == SHORTCUT_TYPE_KEY_ENTRY && + item && item->command != NULL && item->editable) + can_remove = TRUE; + } + + gtk_widget_set_sensitive (button, can_remove); +} + +static void +fill_xkb_options_shortcuts (GtkTreeModel *model) +{ + GList *l; + GtkTreeIter iter; + + for (l = cc_keyboard_option_get_all (); l; l = l->next) + { + CcKeyboardOption *option = l->data; + + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + DETAIL_DESCRIPTION_COLUMN, cc_keyboard_option_get_description (option), + DETAIL_KEYENTRY_COLUMN, option, + DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_XKB_OPTION, + -1); + } +} + +static void +section_selection_changed (GtkTreeSelection *selection, gpointer data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkBuilder *builder = GTK_BUILDER (data); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + GPtrArray *keys; + GtkWidget *shortcut_treeview; + GtkTreeModel *shortcut_model; + gchar *id; + BindingGroupType group; + gint i; + + gtk_tree_model_get (model, &iter, + SECTION_ID_COLUMN, &id, + SECTION_GROUP_COLUMN, &group, -1); + + keys = g_hash_table_lookup (get_hash_for_group (group), id); + if (keys == NULL) + { + g_warning ("Can't find section %s in sections hash table.", id); + g_free (id); + return; + } + + gtk_widget_set_sensitive (WID (builder, "remove-toolbutton"), FALSE); + + /* Fill the shortcut treeview with the keys for the selected section */ + shortcut_treeview = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut_treeview")); + shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (shortcut_treeview)); + gtk_list_store_clear (GTK_LIST_STORE (shortcut_model)); + + for (i = 0; i < keys->len; i++) + { + GtkTreeIter new_row; + CcKeyboardItem *item = g_ptr_array_index (keys, i); + + gtk_list_store_append (GTK_LIST_STORE (shortcut_model), &new_row); + gtk_list_store_set (GTK_LIST_STORE (shortcut_model), &new_row, + DETAIL_DESCRIPTION_COLUMN, item->description, + DETAIL_KEYENTRY_COLUMN, item, + DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_KEY_ENTRY, + -1); + } + + if (g_str_equal (id, "Typing")) + fill_xkb_options_shortcuts (shortcut_model); + + g_free (id); + } +} + +static gboolean +edit_custom_shortcut (CcKeyboardItem *item) +{ + gint result; + gboolean ret; + GSettings *settings; + + settings = g_settings_new_with_path (item->schema, item->gsettings_path); + + g_settings_bind (settings, "name", + G_OBJECT (custom_shortcut_name_entry), "text", + G_SETTINGS_BIND_DEFAULT); + gtk_widget_grab_focus (custom_shortcut_name_entry); + + g_settings_bind (settings, "command", + G_OBJECT (custom_shortcut_command_entry), "text", + G_SETTINGS_BIND_DEFAULT); + + g_settings_delay (settings); + + gtk_window_present (GTK_WINDOW (custom_shortcut_dialog)); + result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog)); + switch (result) + { + case GTK_RESPONSE_OK: + g_settings_apply (settings); + ret = TRUE; + break; + default: + g_settings_revert (settings); + ret = FALSE; + break; + } + + g_settings_unbind (G_OBJECT (custom_shortcut_name_entry), "text"); + g_settings_unbind (G_OBJECT (custom_shortcut_command_entry), "text"); + + g_object_unref (settings); + + gtk_widget_hide (custom_shortcut_dialog); + + return ret; +} + +static gboolean +remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter) +{ + CcKeyboardItem *item; + GPtrArray *keys_array; + GVariantBuilder builder; + char **settings_paths; + int i; + + gtk_tree_model_get (model, iter, + DETAIL_KEYENTRY_COLUMN, &item, + -1); + + /* not a custom shortcut */ + g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH); + + g_settings_delay (item->settings); + g_settings_reset (item->settings, "name"); + g_settings_reset (item->settings, "command"); + g_settings_reset (item->settings, "binding"); + g_settings_apply (item->settings); + g_settings_sync (); + + settings_paths = g_settings_get_strv (binding_settings, "custom-keybindings"); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + for (i = 0; settings_paths[i]; i++) + if (strcmp (settings_paths[i], item->gsettings_path) != 0) + g_variant_builder_add (&builder, "s", settings_paths[i]); + g_settings_set_value (binding_settings, + "custom-keybindings", g_variant_builder_end (&builder)); + g_strfreev (settings_paths); + g_object_unref (item); + + keys_array = g_hash_table_lookup (get_hash_for_group (BINDING_GROUP_USER), CUSTOM_SHORTCUTS_ID); + g_ptr_array_remove (keys_array, item); + + gtk_list_store_remove (GTK_LIST_STORE (model), iter); + + return TRUE; +} + +static void +update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter) +{ + CcKeyboardItem *item; + + gtk_tree_model_get (model, iter, + DETAIL_KEYENTRY_COLUMN, &item, + -1); + + g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH); + + edit_custom_shortcut (item); + if (item->command == NULL || item->command[0] == '\0') + { + remove_custom_shortcut (model, iter); + } + else + { + gtk_list_store_set (GTK_LIST_STORE (model), iter, + DETAIL_KEYENTRY_COLUMN, item, -1); + } +} + +static gboolean +start_editing_cb (GtkTreeView *tree_view, + GdkEventButton *event, + gpointer user_data) +{ + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkCellRenderer *cell = user_data; + + if (event->window != gtk_tree_view_get_bin_window (tree_view)) + return FALSE; + + if (gtk_tree_view_get_path_at_pos (tree_view, + (gint) event->x, + (gint) event->y, + &path, &column, + NULL, NULL)) + { + GtkTreeModel *model; + GtkTreeIter iter; + CcKeyboardItem *item; + ShortcutType type; + + model = gtk_tree_view_get_model (tree_view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + DETAIL_KEYENTRY_COLUMN, &item, + DETAIL_TYPE_COLUMN, &type, + -1); + + if (type == SHORTCUT_TYPE_XKB_OPTION) + { + gtk_tree_path_free (path); + return FALSE; + } + + /* if only the accel can be edited on the selected row + * always select the accel column */ + if (item->desc_editable && + column == gtk_tree_view_get_column (tree_view, 0)) + { + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + gtk_tree_view_set_cursor (tree_view, + path, + column, + FALSE); + update_custom_shortcut (model, &iter); + } + else + { + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + gtk_tree_view_set_cursor_on_cell (tree_view, + path, + gtk_tree_view_get_column (tree_view, 1), + cell, + TRUE); + } + g_signal_stop_emission_by_name (tree_view, "button_press_event"); + gtk_tree_path_free (path); + } + return TRUE; +} + +static void +start_editing_kb_cb (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + CcKeyboardItem *item; + ShortcutType type; + GtkCellRenderer *cell = user_data; + + model = gtk_tree_view_get_model (treeview); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + DETAIL_KEYENTRY_COLUMN, &item, + DETAIL_TYPE_COLUMN, &type, + -1); + + if (type == SHORTCUT_TYPE_XKB_OPTION) + return; + + /* if only the accel can be edited on the selected row + * always select the accel column */ + if (item->desc_editable && + column == gtk_tree_view_get_column (treeview, 0)) + { + gtk_widget_grab_focus (GTK_WIDGET (treeview)); + gtk_tree_view_set_cursor (treeview, + path, + column, + FALSE); + update_custom_shortcut (model, &iter); + } + else + { + gtk_widget_grab_focus (GTK_WIDGET (treeview)); + gtk_tree_view_set_cursor_on_cell (treeview, + path, + gtk_tree_view_get_column (treeview, 1), + cell, + TRUE); + } +} + +static const guint forbidden_keyvals[] = { + /* Navigation keys */ + GDK_KEY_Home, + GDK_KEY_Left, + GDK_KEY_Up, + GDK_KEY_Right, + GDK_KEY_Down, + GDK_KEY_Page_Up, + GDK_KEY_Page_Down, + GDK_KEY_End, + GDK_KEY_Tab, + + /* Return */ + GDK_KEY_KP_Enter, + GDK_KEY_Return, + + GDK_KEY_space, + GDK_KEY_Mode_switch +}; + +static char* +binding_name (guint keyval, + guint keycode, + GdkModifierType mask, + gboolean translate) +{ + if (keyval != 0 || keycode != 0) + return translate ? + gtk_accelerator_get_label_with_keycode (NULL, keyval, keycode, mask) : + gtk_accelerator_name_with_keycode (NULL, keyval, keycode, mask); + else + return g_strdup (translate ? _("Disabled") : ""); +} + +static gboolean +keyval_is_forbidden (guint keyval) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) { + if (keyval == forbidden_keyvals[i]) + return TRUE; + } + + return FALSE; +} + +typedef struct { + CcKeyboardItem *orig_item; + CcKeyboardItem *conflict_item; + guint new_keyval; + GdkModifierType new_mask; + guint new_keycode; +} CcUniquenessData; + +static gboolean +compare_keys_for_uniqueness (CcKeyboardItem *element, + CcUniquenessData *data) +{ + CcKeyboardItem *orig_item; + + orig_item = data->orig_item; + + /* no conflict for : blanks, different modifiers, or ourselves */ + if (element == NULL || data->new_mask != element->mask || + cc_keyboard_item_equal (orig_item, element)) + return FALSE; + + if (data->new_keyval != 0) { + if (data->new_keyval != element->keyval) + return FALSE; + } else if (element->keyval != 0 || data->new_keycode != element->keycode) + return FALSE; + + data->conflict_item = element; + + return TRUE; +} + +static gboolean +cb_check_for_uniqueness (gpointer key, + GPtrArray *keys_array, + CcUniquenessData *data) +{ + guint i; + + for (i = 0; i < keys_array->len; i++) + { + CcKeyboardItem *item; + + item = keys_array->pdata[i]; + if (compare_keys_for_uniqueness (item, data)) + return TRUE; + } + return FALSE; +} + +static void +accel_edited_callback (GtkCellRendererText *cell, + const char *path_string, + guint keyval, + GdkModifierType mask, + guint keycode, + GtkTreeView *view) +{ + GtkTreeModel *model; + GtkTreePath *path = gtk_tree_path_new_from_string (path_string); + GtkTreeIter iter; + CcUniquenessData data; + CcKeyboardItem *item; + char *str; + + model = gtk_tree_view_get_model (view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + gtk_tree_model_get (model, &iter, + DETAIL_KEYENTRY_COLUMN, &item, + -1); + + /* sanity check */ + if (item == NULL) + return; + + /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */ + mask &= ~GDK_LOCK_MASK; + + data.orig_item = item; + data.new_keyval = keyval; + data.new_mask = mask; + data.new_keycode = keycode; + data.conflict_item = NULL; + + if (keyval != 0 || keycode != 0) /* any number of shortcuts can be disabled */ + { + BindingGroupType i; + + for (i = BINDING_GROUP_SYSTEM; i <= BINDING_GROUP_USER && data.conflict_item == NULL; i++) + { + GHashTable *table; + + table = get_hash_for_group (i); + if (!table) + continue; + g_hash_table_find (table, (GHRFunc) cb_check_for_uniqueness, &data); + } + } + + /* Check for unmodified keys */ + if ((mask == 0 || mask == GDK_SHIFT_MASK) && keycode != 0) + { + if ((keyval >= GDK_KEY_a && keyval <= GDK_KEY_z) + || (keyval >= GDK_KEY_A && keyval <= GDK_KEY_Z) + || (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) + || (keyval >= GDK_KEY_kana_fullstop && keyval <= GDK_KEY_semivoicedsound) + || (keyval >= GDK_KEY_Arabic_comma && keyval <= GDK_KEY_Arabic_sukun) + || (keyval >= GDK_KEY_Serbian_dje && keyval <= GDK_KEY_Cyrillic_HARDSIGN) + || (keyval >= GDK_KEY_Greek_ALPHAaccent && keyval <= GDK_KEY_Greek_omega) + || (keyval >= GDK_KEY_hebrew_doublelowline && keyval <= GDK_KEY_hebrew_taf) + || (keyval >= GDK_KEY_Thai_kokai && keyval <= GDK_KEY_Thai_lekkao) + || (keyval >= GDK_KEY_Hangul && keyval <= GDK_KEY_Hangul_Special) + || (keyval >= GDK_KEY_Hangul_Kiyeog && keyval <= GDK_KEY_Hangul_J_YeorinHieuh) + || keyval_is_forbidden (keyval)) { + GtkWidget *dialog; + char *name; + + name = binding_name (keyval, keycode, mask, TRUE); + + dialog = + gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n" + "Please try with a key such as Control, Alt or Shift at the same time."), + name); + + g_free (name); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + /* set it back to its previous value. */ + g_object_set (G_OBJECT (cell), + "accel-key", item->keyval, + "keycode", item->keycode, + "accel-mods", item->mask, + NULL); + return; + } + } + + /* flag to see if the new accelerator was in use by something */ + if (data.conflict_item != NULL) + { + GtkWidget *dialog; + char *name; + int response; + + name = binding_name (keyval, keycode, mask, TRUE); + + dialog = + gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + _("The shortcut \"%s\" is already used for\n\"%s\""), + name, data.conflict_item->description); + g_free (name); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut " + "will be disabled."), + item->description, + data.conflict_item->description); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Reassign"), + GTK_RESPONSE_ACCEPT); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (response == GTK_RESPONSE_ACCEPT) + { + g_object_set (G_OBJECT (data.conflict_item), "binding", "", NULL); + + str = binding_name (keyval, keycode, mask, FALSE); + g_object_set (G_OBJECT (item), "binding", str, NULL); + + g_free (str); + } + else + { + /* set it back to its previous value. */ + g_object_set (G_OBJECT (cell), + "accel-key", item->keyval, + "keycode", item->keycode, + "accel-mods", item->mask, + NULL); + } + + return; + } + + str = binding_name (keyval, keycode, mask, FALSE); + g_object_set (G_OBJECT (item), "binding", str, NULL); + + g_free (str); +} + +static void +accel_cleared_callback (GtkCellRendererText *cell, + const char *path_string, + gpointer data) +{ + GtkTreeView *view = (GtkTreeView *) data; + GtkTreePath *path = gtk_tree_path_new_from_string (path_string); + CcKeyboardItem *item; + GtkTreeIter iter; + GtkTreeModel *model; + + model = gtk_tree_view_get_model (view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + gtk_tree_model_get (model, &iter, + DETAIL_KEYENTRY_COLUMN, &item, + -1); + + /* sanity check */ + if (item == NULL) + return; + + /* Unset the key */ + g_object_set (G_OBJECT (item), "binding", "", NULL); +} + +static gchar * +find_free_settings_path () +{ + char **used_names; + char *dir = NULL; + int i, num, n_names; + + used_names = g_settings_get_strv (binding_settings, "custom-keybindings"); + n_names = g_strv_length (used_names); + + for (num = 0; dir == NULL; num++) + { + char *tmp; + gboolean found = FALSE; + + tmp = g_strdup_printf ("%s/custom%d/", CUSTOM_KEYS_BASENAME, num); + for (i = 0; i < n_names && !found; i++) + found = strcmp (used_names[i], tmp) == 0; + + if (!found) + dir = tmp; + else + g_free (tmp); + } + + return dir; +} + +static void +add_custom_shortcut (GtkTreeView *tree_view, + GtkTreeModel *model) +{ + CcKeyboardItem *item; + GtkTreePath *path; + gchar *settings_path; + + item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH); + + settings_path = find_free_settings_path (); + cc_keyboard_item_load_from_gsettings_path (item, settings_path, TRUE); + g_free (settings_path); + + item->model = model; + + if (edit_custom_shortcut (item) && + item->command && item->command[0]) + { + GPtrArray *keys_array; + GtkTreeIter iter; + GHashTable *hash; + GVariantBuilder builder; + char **settings_paths; + int i; + + hash = get_hash_for_group (BINDING_GROUP_USER); + keys_array = g_hash_table_lookup (hash, CUSTOM_SHORTCUTS_ID); + if (keys_array == NULL) + { + keys_array = g_ptr_array_new (); + g_hash_table_insert (hash, g_strdup (CUSTOM_SHORTCUTS_ID), keys_array); + } + + g_ptr_array_add (keys_array, item); + + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, DETAIL_KEYENTRY_COLUMN, item, -1); + + settings_paths = g_settings_get_strv (binding_settings, "custom-keybindings"); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + for (i = 0; settings_paths[i]; i++) + g_variant_builder_add (&builder, "s", settings_paths[i]); + g_variant_builder_add (&builder, "s", item->gsettings_path); + g_settings_set_value (binding_settings, "custom-keybindings", + g_variant_builder_end (&builder)); + + /* make the new shortcut visible */ + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_expand_to_path (tree_view, path); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0); + gtk_tree_path_free (path); + } + else + { + g_object_unref (item); + } +} + +static void +add_button_clicked (GtkWidget *button, + GtkBuilder *builder) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeModel *section_model; + GtkTreeIter iter; + gboolean found, cont; + + treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, + "shortcut_treeview")); + model = gtk_tree_view_get_model (treeview); + + /* Select the Custom Shortcuts section + * before adding the shortcut itself */ + section_model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID (builder, "section_treeview"))); + cont = gtk_tree_model_get_iter_first (section_model, &iter); + found = FALSE; + while (cont) + { + BindingGroupType group; + + gtk_tree_model_get (section_model, &iter, + SECTION_GROUP_COLUMN, &group, + -1); + + if (group == BINDING_GROUP_USER) + { + found = TRUE; + break; + } + cont = gtk_tree_model_iter_next (section_model, &iter); + } + if (found) + { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID (builder, "section_treeview"))); + gtk_tree_selection_select_iter (selection, &iter); + } + + /* And add the shortcut */ + add_custom_shortcut (treeview, model); +} + +static void +remove_button_clicked (GtkWidget *button, + GtkBuilder *builder) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, + "shortcut_treeview")); + model = gtk_tree_view_get_model (treeview); + + selection = gtk_tree_view_get_selection (treeview); + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + remove_custom_shortcut (model, &iter); + } +} + +static int +section_sort_item (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) +{ + char *a_desc; + int a_group; + char *b_desc; + int b_group; + int ret; + + gtk_tree_model_get (model, a, + SECTION_DESCRIPTION_COLUMN, &a_desc, + SECTION_GROUP_COLUMN, &a_group, + -1); + gtk_tree_model_get (model, b, + SECTION_DESCRIPTION_COLUMN, &b_desc, + SECTION_GROUP_COLUMN, &b_group, + -1); + + if (a_group == b_group && a_desc && b_desc) + ret = g_utf8_collate (a_desc, b_desc); + else + ret = a_group - b_group; + + g_free (a_desc); + g_free (b_desc); + + return ret; +} + +static gboolean +sections_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + BindingGroupType type; + + gtk_tree_model_get (model, iter, SECTION_GROUP_COLUMN, &type, -1); + + return type == BINDING_GROUP_SEPARATOR; +} + +static void +xkb_options_combo_changed (GtkCellRendererCombo *combo, + gchar *model_path, + GtkTreeIter *model_iter, + gpointer data) +{ + GtkTreeView *shortcut_treeview; + GtkTreeModel *shortcut_model; + GtkTreeIter shortcut_iter; + GtkTreeSelection *selection; + CcKeyboardOption *option; + ShortcutType type; + GtkBuilder *builder = data; + + shortcut_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")); + selection = gtk_tree_view_get_selection (shortcut_treeview); + if (!gtk_tree_selection_get_selected (selection, &shortcut_model, &shortcut_iter)) + return; + + gtk_tree_model_get (shortcut_model, &shortcut_iter, + DETAIL_KEYENTRY_COLUMN, &option, + DETAIL_TYPE_COLUMN, &type, + -1); + + if (type != SHORTCUT_TYPE_XKB_OPTION) + return; + + cc_keyboard_option_set_selection (option, model_iter); +} + +static gboolean +poke_xkb_option_row (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer option) +{ + gpointer item; + + gtk_tree_model_get (model, iter, + DETAIL_KEYENTRY_COLUMN, &item, + -1); + + if (item != option) + return FALSE; + + gtk_tree_model_row_changed (model, path, iter); + return TRUE; +} + +static void +xkb_option_changed (CcKeyboardOption *option, + gpointer data) +{ + GtkTreeModel *model = data; + + gtk_tree_model_foreach (model, poke_xkb_option_row, option); +} + +static void +setup_keyboard_options (GtkListStore *store) +{ + GList *l; + + for (l = cc_keyboard_option_get_all (); l; l = l->next) + g_signal_connect (l->data, "changed", + G_CALLBACK (xkb_option_changed), store); +} + +static void +setup_dialog (CcPanel *panel, GtkBuilder *builder) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkWidget *widget; + GtkTreeView *treeview; + GtkTreeSelection *selection; + CcShell *shell; + GtkListStore *model; + GtkTreeModelSort *sort_model; + GtkStyleContext *context; + + gtk_widget_set_size_request (GTK_WIDGET (panel), -1, 400); + + /* Setup the section treeview */ + treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview")); + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (treeview), + sections_separator_func, + panel, + NULL); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Section"), + renderer, + "text", SECTION_DESCRIPTION_COLUMN, + NULL); + g_object_set (renderer, + "width-chars", 20, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + + gtk_tree_view_append_column (treeview, column); + + model = gtk_list_store_new (SECTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); + sort_model = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model))); + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (sort_model)); + g_object_unref (model); + + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model), + SECTION_DESCRIPTION_COLUMN, + section_sort_item, + panel, + NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), + SECTION_DESCRIPTION_COLUMN, + GTK_SORT_ASCENDING); + g_object_unref (sort_model); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + + g_signal_connect (selection, "changed", + G_CALLBACK (section_selection_changed), builder); + section_selection_changed (selection, builder); + + /* Setup the shortcut treeview */ + treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, + "shortcut_treeview")); + + binding_settings = g_settings_new (BINDINGS_SCHEMA); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + column = gtk_tree_view_column_new_with_attributes (NULL, renderer, NULL); + gtk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL, NULL); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_expand (column, TRUE); + + gtk_tree_view_append_column (treeview, column); + + renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, + "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, + NULL); + + g_signal_connect (treeview, "button_press_event", + G_CALLBACK (start_editing_cb), renderer); + g_signal_connect (treeview, "row-activated", + G_CALLBACK (start_editing_kb_cb), renderer); + + g_signal_connect (renderer, "accel_edited", + G_CALLBACK (accel_edited_callback), + treeview); + g_signal_connect (renderer, "accel_cleared", + G_CALLBACK (accel_cleared_callback), + treeview); + + column = gtk_tree_view_column_new_with_attributes (NULL, renderer, NULL); + gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_expand (column, FALSE); + + renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_COMBO, + "has-entry", FALSE, + "text-column", XKB_OPTION_DESCRIPTION_COLUMN, + "editable", TRUE, + "ellipsize", PANGO_ELLIPSIZE_END, + "width-chars", 25, + NULL); + g_signal_connect (renderer, "changed", + G_CALLBACK (xkb_options_combo_changed), builder); + + gtk_tree_view_column_pack_end (column, renderer, FALSE); + + gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL); + + gtk_tree_view_append_column (treeview, column); + + model = gtk_list_store_new (DETAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT); + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model)); + g_object_unref (model); + + setup_keyboard_options (model); + + widget = GTK_WIDGET (gtk_builder_get_object (builder, "actions_swindow")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + widget = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut-toolbar")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + /* set up the dialog */ + shell = cc_panel_get_shell (CC_PANEL (panel)); + widget = cc_shell_get_toplevel (shell); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect (selection, "changed", + G_CALLBACK (shortcut_selection_changed), + WID (builder, "remove-toolbutton")); + + /* setup the custom shortcut dialog */ + custom_shortcut_dialog = WID (builder, + "custom-shortcut-dialog"); + custom_shortcut_name_entry = WID (builder, + "custom-shortcut-name-entry"); + custom_shortcut_command_entry = WID (builder, + "custom-shortcut-command-entry"); + g_signal_connect (WID (builder, "add-toolbutton"), + "clicked", G_CALLBACK (add_button_clicked), builder); + g_signal_connect (WID (builder, "remove-toolbutton"), + "clicked", G_CALLBACK (remove_button_clicked), builder); + + gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog), + GTK_RESPONSE_OK); + + gtk_window_set_transient_for (GTK_WINDOW (custom_shortcut_dialog), + GTK_WINDOW (widget)); + + gtk_window_set_resizable (GTK_WINDOW (custom_shortcut_dialog), FALSE); +} + +static void +on_window_manager_change (const char *wm_name, CcPanel *panel) +{ + reload_sections (panel); +} + +void +keyboard_shortcuts_init (CcPanel *panel, GtkBuilder *builder) +{ + g_object_set_data (G_OBJECT (panel), "builder", builder); + wm_common_register_window_manager_change ((GFunc) on_window_manager_change, + panel); + setup_dialog (panel, builder); + reload_sections (panel); +} + +gboolean +keyboard_shortcuts_set_section (CcPanel *panel, const char *section) +{ + GtkBuilder *builder; + GtkTreeModel *section_model; + GtkTreeIter iter; + gboolean found, cont; + + builder = g_object_get_data (G_OBJECT (panel), "builder"); + if (builder == NULL) + { + /* Remember the section name to be set later */ + g_object_set_data_full (G_OBJECT (panel), "section-to-set", g_strdup (section), g_free); + return TRUE; + } + section_model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID (builder, "section_treeview"))); + cont = gtk_tree_model_get_iter_first (section_model, &iter); + found = FALSE; + while (cont) + { + char *id; + + gtk_tree_model_get (section_model, &iter, + SECTION_ID_COLUMN, &id, + -1); + + if (g_strcmp0 (id, section) == 0) + { + found = TRUE; + g_free (id); + break; + } + g_free (id); + cont = gtk_tree_model_iter_next (section_model, &iter); + } + if (found) + { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID (builder, "section_treeview"))); + gtk_tree_selection_select_iter (selection, &iter); + } + else + { + g_warning ("Could not find section '%s' to switch to.", section); + } + + return found; +} + +void +keyboard_shortcuts_dispose (CcPanel *panel) +{ + if (kb_system_sections != NULL) + { + g_hash_table_destroy (kb_system_sections); + kb_system_sections = NULL; + } + if (kb_apps_sections != NULL) + { + g_hash_table_destroy (kb_apps_sections); + kb_apps_sections = NULL; + } + if (kb_user_sections != NULL) + { + g_hash_table_destroy (kb_user_sections); + kb_user_sections = NULL; + } + + g_clear_object (&binding_settings); + + cc_keyboard_option_clear_all (); +} diff -Nru gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-password-dialog.c gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-password-dialog.c --- gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-password-dialog.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-password-dialog.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,708 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "um-password-dialog.h" +#include "um-user-manager.h" +#include "um-utils.h" +#include "run-passwd.h" +#include "pw-utils.h" + +struct _UmPasswordDialog { + GtkWidget *dialog; + GtkWidget *user_icon; + GtkWidget *user_name; + GtkWidget *action_label; + GtkWidget *action_combo; + GtkWidget *password_entry; + GtkWidget *verify_entry; + GtkWidget *strength_indicator; + GtkWidget *strength_indicator_label; + GtkWidget *normal_hint_entry; + GtkWidget *normal_hint_label; + GtkWidget *show_password_button; + GtkWidget *ok_button; + + UmUser *user; + + GtkWidget *old_password_label; + GtkWidget *old_password_entry; + gboolean old_password_ok; + + PasswdHandler *passwd_handler; + + gchar **generated; + gint next_generated; +}; + +static void +generate_one_password (GtkWidget *widget, + UmPasswordDialog *um) +{ + gchar *pwd; + + pwd = pw_generate (); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), pwd); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + + g_free (pwd); +} + +static void +activate_icon (GtkEntry *entry, + GtkEntryIconPosition pos, + GdkEventButton *event, + UmPasswordDialog *um) +{ + generate_one_password (GTK_WIDGET (entry), um); +} + +static void +populate_menu (GtkEntry *entry, + GtkMenu *menu, + UmPasswordDialog *um) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_mnemonic (_("_Generate a password")); + g_signal_connect (item, "activate", + G_CALLBACK (generate_one_password), um); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); +} + +static void +finish_password_change (UmPasswordDialog *um) +{ + gtk_widget_hide (um->dialog); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), " "); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + + um_password_dialog_set_user (um, NULL); +} + +static void +cancel_password_dialog (GtkButton *button, + UmPasswordDialog *um) +{ + finish_password_change (um); +} + +static void +dialog_closed (GtkWidget *dialog, + gint response_id, + UmPasswordDialog *um) +{ + gtk_widget_destroy (dialog); +} + +static void +password_changed_cb (PasswdHandler *handler, + GError *error, + UmPasswordDialog *um) +{ + GtkWidget *dialog; + const gchar *primary_text; + const gchar *secondary_text; + + gtk_widget_set_sensitive (um->dialog, TRUE); + gdk_window_set_cursor (gtk_widget_get_window (um->dialog), NULL); + + if (!error) { + finish_password_change (um); + return; + } + + if (error->code == PASSWD_ERROR_REJECTED) { + primary_text = error->message; + secondary_text = _("Please choose another password."); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), ""); + gtk_widget_grab_focus (um->password_entry); + + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + } + else if (error->code == PASSWD_ERROR_AUTH_FAILED) { + primary_text = error->message; + secondary_text = _("Please type your current password again."); + + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + gtk_widget_grab_focus (um->old_password_entry); + } + else { + primary_text = _("Password could not be changed"); + secondary_text = error->message; + } + + dialog = gtk_message_dialog_new (GTK_WINDOW (um->dialog), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary_text); + g_signal_connect (dialog, "response", + G_CALLBACK (dialog_closed), um); + gtk_window_present (GTK_WINDOW (dialog)); + +} + +static void +accept_password_dialog (GtkButton *button, + UmPasswordDialog *um) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gint mode; + const gchar *hint; + const gchar *password; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo)); + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->action_combo), &iter); + gtk_tree_model_get (model, &iter, 1, &mode, -1); + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + hint = gtk_entry_get_text (GTK_ENTRY (um->normal_hint_entry)); + + if (mode == 0 && um_user_get_uid (um->user) == getuid ()) { + GdkDisplay *display; + GdkCursor *cursor; + + /* When setting a password for the current user, + * use passwd directly, to preserve the audit trail + * and to e.g. update the keyring password. + */ + passwd_change_password (um->passwd_handler, password, (PasswdCallback) password_changed_cb, um); + gtk_widget_set_sensitive (um->dialog, FALSE); + display = gtk_widget_get_display (um->dialog); + cursor = gdk_cursor_new_for_display (display, GDK_WATCH); + gdk_window_set_cursor (gtk_widget_get_window (um->dialog), cursor); + gdk_display_flush (display); + g_object_unref (cursor); + } + else { + um_user_set_password (um->user, mode, password, hint); + finish_password_change (um); + } +} + +static void +update_sensitivity (UmPasswordDialog *um) +{ + const gchar *password, *verify; + const gchar *old_password; + const gchar *tooltip; + gboolean can_change; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry)); + old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry)); + + if (strlen (password) < pw_min_length ()) { + can_change = FALSE; + if (password[0] == '\0') { + tooltip = _("You need to enter a new password"); + } + else { + tooltip = _("The new password is too short"); + } + } + else if (strcmp (password, verify) != 0) { + can_change = FALSE; + if (verify[0] == '\0') { + tooltip = _("You need to confirm the password"); + } + else { + tooltip = _("The passwords do not match"); + } + } + else if (!um->old_password_ok) { + can_change = FALSE; + if (old_password[0] == '\0') { + tooltip = _("You need to enter your current password"); + } + else { + tooltip = _("The current password is not correct"); + } + } + else { + can_change = TRUE; + tooltip = NULL; + } + + gtk_widget_set_sensitive (um->ok_button, can_change); + gtk_widget_set_tooltip_text (um->ok_button, tooltip); +} + +static void +action_changed (GtkComboBox *combo, + UmPasswordDialog *um) +{ + gint active; + + active = gtk_combo_box_get_active (combo); + if (active == 0) { + gtk_widget_set_sensitive (um->password_entry, TRUE); + gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, TRUE); + gtk_widget_set_sensitive (um->verify_entry, TRUE); + gtk_widget_set_sensitive (um->old_password_entry, TRUE); + gtk_widget_set_sensitive (um->normal_hint_entry, TRUE); + gtk_widget_set_sensitive (um->normal_hint_label, TRUE); + gtk_widget_set_sensitive (um->strength_indicator_label, TRUE); + gtk_widget_set_sensitive (um->show_password_button, TRUE); + + update_sensitivity (um); + } + else { + gtk_widget_set_sensitive (um->password_entry, FALSE); + gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, FALSE); + gtk_widget_set_sensitive (um->verify_entry, FALSE); + gtk_widget_set_sensitive (um->old_password_entry, FALSE); + gtk_widget_set_sensitive (um->normal_hint_entry, FALSE); + gtk_widget_set_sensitive (um->normal_hint_label, FALSE); + gtk_widget_set_sensitive (um->strength_indicator_label, FALSE); + gtk_widget_set_sensitive (um->show_password_button, FALSE); + gtk_widget_set_sensitive (um->ok_button, TRUE); + } +} + +static void +show_password_toggled (GtkToggleButton *button, + UmPasswordDialog *um) +{ + gboolean active; + + active = gtk_toggle_button_get_active (button); + gtk_entry_set_visibility (GTK_ENTRY (um->password_entry), active); + gtk_entry_set_visibility (GTK_ENTRY (um->verify_entry), active); +} + +static void +update_password_strength (UmPasswordDialog *um) +{ + const gchar *password; + const gchar *old_password; + const gchar *username; + gint strength_level; + const gchar *hint; + const gchar *long_hint; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry)); + username = um_user_get_user_name (um->user); + + pw_strength (password, old_password, username, + &hint, &long_hint, &strength_level); + + gtk_level_bar_set_value (GTK_LEVEL_BAR (um->strength_indicator), strength_level); + gtk_label_set_label (GTK_LABEL (um->strength_indicator_label), hint); + gtk_widget_set_tooltip_text (um->strength_indicator, long_hint); + gtk_widget_set_tooltip_text (um->strength_indicator_label, long_hint); +} + +static void +update_password_match (UmPasswordDialog *um) +{ + const char *password; + const char *verify; + + password = gtk_entry_get_text (GTK_ENTRY (um->password_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry)); + + if (strlen (password) > 0 && strlen (verify) > 0) { + if (strcmp (password, verify) != 0) { + set_entry_validation_error (GTK_ENTRY (um->verify_entry), + _("Passwords do not match")); + } + else { + clear_entry_validation_error (GTK_ENTRY (um->verify_entry)); + } + } +} + +static void +password_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + update_password_strength (um); + update_sensitivity (um); + update_password_match (um); +} + +static gboolean +password_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + update_password_match (um); + return FALSE; +} + +static void +verify_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + clear_entry_validation_error (GTK_ENTRY (entry)); + update_password_strength (um); + update_sensitivity (um); +} + +static gboolean +verify_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + update_password_match (um); + return FALSE; +} + +static void +entry_size_changed (GtkWidget *entry, + GtkAllocation *allocation, + GtkWidget *label) +{ + gtk_widget_set_size_request (label, allocation->width, -1); +} + +static void +auth_cb (PasswdHandler *handler, + GError *error, + UmPasswordDialog *um) +{ + if (error) { + um->old_password_ok = FALSE; + set_entry_validation_error (GTK_ENTRY (um->old_password_entry), + _("Wrong password")); + } + else { + um->old_password_ok = TRUE; + clear_entry_validation_error (GTK_ENTRY (um->old_password_entry)); + } + + update_sensitivity (um); +} + +static gboolean +old_password_entry_focus_out (GtkWidget *entry, + GdkEventFocus *event, + UmPasswordDialog *um) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + if (strlen (text) > 0) { + passwd_authenticate (um->passwd_handler, text, + (PasswdCallback)auth_cb, um); + } + + return FALSE; +} + +static void +old_password_entry_activate (GtkWidget *entry, + UmPasswordDialog *um) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + if (strlen (text) > 0) { + passwd_authenticate (um->passwd_handler, text, + (PasswdCallback)auth_cb, um); + } +} + + +static void +old_password_entry_changed (GtkEntry *entry, + GParamSpec *pspec, + UmPasswordDialog *um) +{ + clear_entry_validation_error (GTK_ENTRY (entry)); + um->old_password_ok = FALSE; + update_sensitivity (um); +} + +void +um_password_dialog_set_privileged (UmPasswordDialog *um, + gboolean privileged) +{ + if (privileged) { + gtk_widget_set_visible (um->action_label, TRUE); + gtk_widget_set_visible (um->action_combo, TRUE); + } + else { + gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0); + gtk_widget_set_visible (um->action_label, FALSE); + gtk_widget_set_visible (um->action_combo, FALSE); + } +} + +UmPasswordDialog * +um_password_dialog_new (void) +{ + GtkBuilder *builder; + GError *error; + const gchar *filename; + UmPasswordDialog *um; + GtkWidget *widget; + const char *old_label; + char *label; + gint len; + + builder = gtk_builder_new (); + + error = NULL; + filename = UIDIR "/password-dialog.ui"; + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + filename = "data/password-dialog.ui"; + if (!gtk_builder_add_from_file (builder, filename, &error)) { + g_error ("%s", error->message); + g_error_free (error); + return NULL; + } + + um = g_new0 (UmPasswordDialog, 1); + + um->action_label = (GtkWidget *) gtk_builder_get_object (builder, "action-label"); + widget = (GtkWidget *) gtk_builder_get_object (builder, "action-combo"); + g_signal_connect (widget, "changed", + G_CALLBACK (action_changed), um); + um->action_combo = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog"); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + um->dialog = widget; + + um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon"); + um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name"); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button"); + g_signal_connect (widget, "clicked", + G_CALLBACK (cancel_password_dialog), um); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button"); + g_signal_connect (widget, "clicked", + G_CALLBACK (accept_password_dialog), um); + gtk_widget_grab_default (widget); + um->ok_button = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label"); + old_label = gtk_label_get_label (GTK_LABEL (widget)); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + label = g_strdup_printf ("%s", + "help:ubuntu-help/user-goodpassword", + old_label); + else + label = g_strdup_printf ("%s", + "help:gnome-help/user-goodpassword", + old_label); + gtk_label_set_markup (GTK_LABEL (widget), label); + g_free (label); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "show-password-checkbutton"); + g_signal_connect (widget, "toggled", + G_CALLBACK (show_password_toggled), um); + um->show_password_button = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "password-entry"); + g_signal_connect (widget, "notify::text", + G_CALLBACK (password_entry_changed), um); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (password_entry_focus_out), um); + gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); + + g_signal_connect (widget, "icon-press", + G_CALLBACK (activate_icon), um); + g_signal_connect (widget, "populate-popup", + G_CALLBACK (populate_menu), um); + + um->password_entry = widget; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "old-password-entry"); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (old_password_entry_focus_out), um); + g_signal_connect (widget, "notify::text", + G_CALLBACK (old_password_entry_changed), um); + g_signal_connect (widget, "activate", + G_CALLBACK (old_password_entry_activate), um); + um->old_password_entry = widget; + um->old_password_label = (GtkWidget *) gtk_builder_get_object (builder, "old-password-label"); + + widget = (GtkWidget *) gtk_builder_get_object (builder, "verify-entry"); + g_signal_connect (widget, "notify::text", + G_CALLBACK (verify_entry_changed), um); + g_signal_connect_after (widget, "focus-out-event", + G_CALLBACK (verify_entry_focus_out), um); + um->verify_entry = widget; + + len = 0; + len = MAX (len, strlen (C_("Password strength", "Too short"))); + len = MAX (len, strlen (C_("Password strength", "Weak"))); + len = MAX (len, strlen (C_("Password strength", "Fair"))); + len = MAX (len, strlen (C_("Password strength", "Good"))); + len = MAX (len, strlen (C_("Password strength", "Strong"))); + len += 2; + + widget = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); + gtk_label_set_width_chars (GTK_LABEL (widget), len); + + um->normal_hint_entry = (GtkWidget *) gtk_builder_get_object (builder, "normal-hint-entry"); + + /* Label size hack. + * This only sort-of works because the dialog is non-resizable. + */ + widget = (GtkWidget *)gtk_builder_get_object (builder, "password-normal-hint-description-label"); + g_signal_connect (um->normal_hint_entry, "size-allocate", + G_CALLBACK (entry_size_changed), widget); + um->normal_hint_label = widget; + + um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator"); + + um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label"); + + g_object_unref (builder); + + return um; +} + +void +um_password_dialog_free (UmPasswordDialog *um) +{ + gtk_widget_destroy (um->dialog); + + if (um->user) + g_object_unref (um->user); + + if (um->passwd_handler) + passwd_destroy (um->passwd_handler); + + g_free (um); +} + +static gboolean +visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + UmPasswordDialog *um) +{ + if (um->user) { + gint mode; + gboolean locked = um_user_get_locked (um->user); + + gtk_tree_model_get (model, iter, 1, &mode, -1); + + if (mode == 3 && locked) + return FALSE; + + if (mode == 4 && !locked) + return FALSE; + + return TRUE; + } + + return TRUE; +} + +void +um_password_dialog_set_user (UmPasswordDialog *um, + UmUser *user) +{ + GdkPixbuf *pixbuf; + GtkTreeModel *model; + + if (um->user) { + g_object_unref (um->user); + um->user = NULL; + } + if (user) { + um->user = g_object_ref (user); + + pixbuf = um_user_render_icon (user, FALSE, 48); + gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf); + g_object_unref (pixbuf); + + gtk_label_set_label (GTK_LABEL (um->user_name), + um_user_get_real_name (user)); + + gtk_entry_set_text (GTK_ENTRY (um->password_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->verify_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), ""); + gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), ""); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), FALSE); + if (um_user_get_uid (um->user) == getuid () && + um_user_get_password_mode (um->user) == UM_PASSWORD_MODE_REGULAR) { + gtk_widget_show (um->old_password_label); + gtk_widget_show (um->old_password_entry); + um->old_password_ok = FALSE; + } + else { + gtk_widget_hide (um->old_password_label); + gtk_widget_hide (um->old_password_entry); + um->old_password_ok = TRUE; + } + if (um_user_get_uid (um->user) == getuid()) { + if (um->passwd_handler != NULL) + passwd_destroy (um->passwd_handler); + um->passwd_handler = passwd_init (); + } + } + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo)); + if (!GTK_IS_TREE_MODEL_FILTER (model)) { + model = gtk_tree_model_filter_new (model, NULL); + gtk_combo_box_set_model (GTK_COMBO_BOX (um->action_combo), model); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model), + (GtkTreeModelFilterVisibleFunc) visible_func, + um, NULL); + } + + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model)); + gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0); +} + +void +um_password_dialog_show (UmPasswordDialog *um, + GtkWindow *parent) +{ + gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent); + gtk_window_present (GTK_WINDOW (um->dialog)); + if (um->old_password_ok == FALSE) + gtk_widget_grab_focus (um->old_password_entry); + else + gtk_widget_grab_focus (um->password_entry); +} + diff -Nru gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-user-panel.c gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-user-panel.c --- gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-user-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-user-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1401 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include "um-user-panel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ + +#include "shell/cc-editable-entry.h" + +#include "um-user.h" +#include "um-user-manager.h" + +#include "um-editable-button.h" +#include "um-editable-combo.h" + +#include "um-account-dialog.h" +#include "cc-language-chooser.h" +#include "um-password-dialog.h" +#include "um-photo-dialog.h" +#include "um-fingerprint-dialog.h" +#include "um-utils.h" + +#include "cc-common-language.h" + +#define USER_ACCOUNTS_PERMISSION "org.gnome.controlcenter.user-accounts.administration" + +CC_PANEL_REGISTER (UmUserPanel, um_user_panel) + +#define UM_USER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), UM_TYPE_USER_PANEL, UmUserPanelPrivate)) + +struct _UmUserPanelPrivate { + UmUserManager *um; + GtkBuilder *builder; + + GtkWidget *main_box; + GPermission *permission; + GtkWidget *language_chooser; + + UmPasswordDialog *password_dialog; + UmPhotoDialog *photo_dialog; +}; + +static GtkWidget * +get_widget (UmUserPanelPrivate *d, const char *name) +{ + return (GtkWidget *)gtk_builder_get_object (d->builder, name); +} + +enum { + USER_COL, + FACE_COL, + NAME_COL, + USER_ROW_COL, + TITLE_COL, + HEADING_ROW_COL, + SORT_KEY_COL, + AUTOLOGIN_COL, + NUM_USER_LIST_COLS +}; + +static UmUser * +get_selected_user (UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *model; + UmUser *user; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + selection = gtk_tree_view_get_selection (tv); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, &user, -1); + return user; + } + + return NULL; +} + +static char * +get_name_col_str (UmUser *user) +{ + return g_markup_printf_escaped ("%s\n%s", + um_user_get_display_name (user), + um_user_get_user_name (user)); +} + +static void +user_added (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkWidget *widget; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeIter iter; + GtkTreeIter dummy; + GdkPixbuf *pixbuf; + gchar *text; + GtkTreeSelection *selection; + gint sort_key; + gboolean is_autologin; + + g_debug ("user added: %d %s\n", um_user_get_uid (user), um_user_get_real_name (user)); + widget = get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + store = GTK_LIST_STORE (model); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + + pixbuf = um_user_render_icon (user, TRUE, 48); + text = get_name_col_str (user); + + is_autologin = um_user_get_automatic_login (user); + + if (um_user_get_uid (user) == getuid ()) { + sort_key = 1; + } + else { + sort_key = 3; + } + gtk_list_store_append (store, &iter); + + gtk_list_store_set (store, &iter, + USER_COL, user, + FACE_COL, pixbuf, + NAME_COL, text, + USER_ROW_COL, TRUE, + TITLE_COL, NULL, + HEADING_ROW_COL, FALSE, + SORT_KEY_COL, sort_key, + AUTOLOGIN_COL, is_autologin, + -1); + g_object_unref (pixbuf); + g_free (text); + + if (sort_key == 1 && + !gtk_tree_selection_get_selected (selection, &model, &dummy)) { + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +get_previous_user_row (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *prev) +{ + GtkTreePath *path; + UmUser *user; + + path = gtk_tree_model_get_path (model, iter); + while (gtk_tree_path_prev (path)) { + gtk_tree_model_get_iter (model, prev, path); + gtk_tree_model_get (model, prev, USER_COL, &user, -1); + if (user) { + g_object_unref (user); + break; + } + } + gtk_tree_path_free (path); +} + +static gboolean +get_next_user_row (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *next) +{ + UmUser *user; + + *next = *iter; + while (gtk_tree_model_iter_next (model, next)) { + gtk_tree_model_get (model, next, USER_COL, &user, -1); + if (user) { + g_object_unref (user); + return TRUE; + } + } + + return FALSE; +} + +static void +user_removed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkListStore *store; + GtkTreeIter iter, next; + UmUser *u; + + g_debug ("user removed: %s\n", um_user_get_user_name (user)); + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + selection = gtk_tree_view_get_selection (tv); + model = gtk_tree_view_get_model (tv); + store = GTK_LIST_STORE (model); + if (gtk_tree_model_get_iter_first (model, &iter)) { + do { + gtk_tree_model_get (model, &iter, USER_COL, &u, -1); + + if (u != NULL) { + if (um_user_get_uid (user) == um_user_get_uid (u)) { + if (!get_next_user_row (model, &iter, &next)) + get_previous_user_row (model, &iter, &next); + gtk_list_store_remove (store, &iter); + gtk_tree_selection_select_iter (selection, &next); + g_object_unref (u); + break; + } + g_object_unref (u); + } + } while (gtk_tree_model_iter_next (model, &iter)); + } +} + +static void show_user (UmUser *user, UmUserPanelPrivate *d); + +static void +user_changed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d) +{ + GtkTreeView *tv; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + UmUser *current; + GdkPixbuf *pixbuf; + char *text; + gboolean is_autologin; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (tv); + selection = gtk_tree_view_get_selection (tv); + + gtk_tree_model_get_iter_first (model, &iter); + do { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + if (current == user) { + pixbuf = um_user_render_icon (user, TRUE, 48); + text = get_name_col_str (user); + is_autologin = um_user_get_automatic_login (user); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + USER_COL, user, + FACE_COL, pixbuf, + NAME_COL, text, + AUTOLOGIN_COL, is_autologin, + -1); + g_object_unref (pixbuf); + g_free (text); + g_object_unref (current); + + break; + } + if (current) + g_object_unref (current); + + } while (gtk_tree_model_iter_next (model, &iter)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + + if (current == user) { + show_user (user, d); + } + if (current) + g_object_unref (current); + } +} + +static void +select_created_user (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + UmUserPanelPrivate *d = user_data; + UmAccountDialog *dialog; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + UmUser *current; + GtkTreePath *path; + UmUser *user; + + dialog = UM_ACCOUNT_DIALOG (object); + user = um_account_dialog_finish (dialog, result); + gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (user == NULL) + return; + + tv = (GtkTreeView *)get_widget (d, "list-treeview"); + model = gtk_tree_view_get_model (tv); + selection = gtk_tree_view_get_selection (tv); + + gtk_tree_model_get_iter_first (model, &iter); + do { + gtk_tree_model_get (model, &iter, USER_COL, ¤t, -1); + if (user == current) { + path = gtk_tree_model_get_path (model, &iter); + gtk_tree_view_scroll_to_cell (tv, path, NULL, FALSE, 0.0, 0.0); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + g_object_unref (current); + break; + } + if (current) + g_object_unref (current); + } while (gtk_tree_model_iter_next (model, &iter)); + + g_object_unref (user); +} + +static void +add_user (GtkButton *button, UmUserPanelPrivate *d) +{ + UmAccountDialog *dialog; + + dialog = um_account_dialog_new (); + um_account_dialog_show (dialog, GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + select_created_user, d); +} + +static void +delete_user_done (UmUserManager *manager, + GAsyncResult *res, + UmUserPanelPrivate *d) +{ + GError *error; + + error = NULL; + if (!um_user_manager_delete_user_finish (manager, res, &error)) { + if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Failed to delete user")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_signal_connect (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_present (GTK_WINDOW (dialog)); + } + g_error_free (error); + } +} + +static void +delete_user_response (GtkWidget *dialog, + gint response_id, + UmUserPanelPrivate *d) +{ + UmUser *user; + gboolean remove_files; + + gtk_widget_destroy (dialog); + + if (response_id == GTK_RESPONSE_CANCEL) { + return; + } + else if (response_id == GTK_RESPONSE_NO) { + remove_files = TRUE; + } + else { + remove_files = FALSE; + } + + user = get_selected_user (d); + + um_user_manager_delete_user (d->um, + user, + remove_files, + (GAsyncReadyCallback)delete_user_done, + d, + NULL); + + g_object_unref (user); +} + +static void +delete_user (GtkButton *button, UmUserPanelPrivate *d) +{ + UmUser *user; + GtkWidget *dialog; + + user = get_selected_user (d); + if (user == NULL) { + return; + } + else if (um_user_get_uid (user) == getuid ()) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("You cannot delete your own account.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + } + else if (um_user_is_logged_in (user)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("%s is still logged in"), + um_user_get_real_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Deleting a user while they are logged in can leave the system in an inconsistent state.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + } + else { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Do you want to keep %s's files?"), + um_user_get_real_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("It is possible to keep the home directory, mail spool and temporary files around when deleting a user account.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Delete Files"), GTK_RESPONSE_NO, + _("_Keep Files"), GTK_RESPONSE_YES, + _("_Cancel"), GTK_RESPONSE_CANCEL, + NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-users"); + + g_signal_connect (dialog, "response", + G_CALLBACK (delete_user_response), d); + } + + g_signal_connect (dialog, "close", + G_CALLBACK (gtk_widget_destroy), NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + gtk_window_present (GTK_WINDOW (dialog)); + + g_object_unref (user); +} + +static const gchar * +get_invisible_text (void) +{ + GtkWidget *entry; + gunichar invisible_char; + static gchar invisible_text[40]; + gchar *p; + gint i; + + entry = gtk_entry_new (); + invisible_char = gtk_entry_get_invisible_char (GTK_ENTRY (entry)); + if (invisible_char == 0) + invisible_char = 0x2022; + + g_object_ref_sink (entry); + g_object_unref (entry); + + /* five bullets */ + p = invisible_text; + for (i = 0; i < 5; i++) + p += g_unichar_to_utf8 (invisible_char, p); + *p = 0; + + return invisible_text; +} + +static const gchar * +get_password_mode_text (UmUser *user) +{ + const gchar *text; + + if (um_user_get_locked (user)) { + text = C_("Password mode", "Account disabled"); + } + else { + switch (um_user_get_password_mode (user)) { + case UM_PASSWORD_MODE_REGULAR: + text = get_invisible_text (); + break; + case UM_PASSWORD_MODE_SET_AT_LOGIN: + text = C_("Password mode", "To be set at next login"); + break; + case UM_PASSWORD_MODE_NONE: + text = C_("Password mode", "None"); + break; + default: + g_assert_not_reached (); + } + } + + return text; +} + +static void +autologin_changed (GObject *object, + GParamSpec *pspec, + UmUserPanelPrivate *d) +{ + gboolean active; + UmUser *user; + + active = gtk_switch_get_active (GTK_SWITCH (object)); + user = get_selected_user (d); + + if (active != um_user_get_automatic_login (user)) { + um_user_set_automatic_login (user, active); + if (um_user_get_automatic_login (user)) { + GSList *list; + GSList *l; + list = um_user_manager_list_users (d->um); + for (l = list; l != NULL; l = l->next) { + UmUser *u = l->data; + if (um_user_get_uid (u) != um_user_get_uid (user)) { + um_user_set_automatic_login (user, FALSE); + } + } + g_slist_free (list); + } + } + + g_object_unref (user); +} + +static void +show_user (UmUser *user, UmUserPanelPrivate *d) +{ + GtkWidget *image; + GtkWidget *label; + GtkWidget *label2; + GtkWidget *label3; + GdkPixbuf *pixbuf; + gchar *lang; + GtkWidget *widget; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean show, enable; + + pixbuf = um_user_render_icon (user, FALSE, 48); + image = get_widget (d, "user-icon-image"); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + image = get_widget (d, "user-icon-image2"); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + g_object_unref (pixbuf); + + um_photo_dialog_set_user (d->photo_dialog, user); + + widget = get_widget (d, "full-name-entry"); + cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), um_user_get_real_name (user)); + gtk_widget_set_tooltip_text (widget, um_user_get_user_name (user)); + + widget = get_widget (d, "account-type-combo"); + um_editable_combo_set_active (UM_EDITABLE_COMBO (widget), um_user_get_account_type (user)); + + widget = get_widget (d, "account-password-button"); + um_editable_button_set_text (UM_EDITABLE_BUTTON (widget), get_password_mode_text (user)); + enable = um_user_is_local_account (user); + gtk_widget_set_sensitive (widget, enable); + + widget = get_widget (d, "autologin-switch"); + g_signal_handlers_block_by_func (widget, autologin_changed, d); + gtk_switch_set_active (GTK_SWITCH (widget), um_user_get_automatic_login (user)); + g_signal_handlers_unblock_by_func (widget, autologin_changed, d); + + if (um_user_get_locked (user)) + gtk_widget_set_sensitive (widget, FALSE); + + widget = get_widget (d, "account-language-combo"); + model = um_editable_combo_get_model (UM_EDITABLE_COMBO (widget)); + cc_add_user_languages (model); + + lang = g_strdup (um_user_get_language (user)); + if (!lang) + lang = cc_common_language_get_current_language (); + cc_common_language_get_iter_for_language (model, lang, &iter); + um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (widget), &iter); + g_free (lang); + + /* Fingerprint: show when self, possible, and local account */ + widget = get_widget (d, "account-fingerprint-notebook"); + label = get_widget (d, "account-fingerprint-label"); + label2 = get_widget (d, "account-fingerprint-value-label"); + label3 = get_widget (d, "account-fingerprint-button-label"); + show = (um_user_get_uid (user) == getuid() && + um_user_is_local_account (user) && + set_fingerprint_label (label2, label3)); + gtk_widget_set_visible (label, show); + gtk_widget_set_visible (widget, show); + + /* Autologin: show when local account */ + widget = get_widget (d, "autologin-switch"); + label = get_widget (d, "autologin-label"); + show = um_user_is_local_account (user); + gtk_widget_set_visible (widget, show); + gtk_widget_set_visible (label, show); +} + +static void on_permission_changed (GPermission *permission, GParamSpec *pspec, gpointer data); + +static void +selected_user_changed (GtkTreeSelection *selection, UmUserPanelPrivate *d) +{ + GtkTreeModel *model; + GtkTreeIter iter; + UmUser *user; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (model, &iter, USER_COL, &user, -1); + show_user (user, d); + if (d->permission != NULL) + on_permission_changed (d->permission, NULL, d); + gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), TRUE); + g_object_unref (user); + } else { + gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), FALSE); + } +} + +static void +change_name_done (GtkWidget *entry, + UmUserPanelPrivate *d) +{ + const gchar *text; + UmUser *user; + + user = get_selected_user (d); + + text = cc_editable_entry_get_text (CC_EDITABLE_ENTRY (entry)); + if (g_strcmp0 (text, um_user_get_real_name (user)) != 0) { + um_user_set_real_name (user, text); + } + + g_object_unref (user); +} + +static void +account_type_changed (UmEditableCombo *combo, + UmUserPanelPrivate *d) +{ + UmUser *user; + GtkTreeModel *model; + GtkTreeIter iter; + gint account_type; + + user = get_selected_user (d); + + model = um_editable_combo_get_model (combo); + um_editable_combo_get_active_iter (combo, &iter); + gtk_tree_model_get (model, &iter, 1, &account_type, -1); + + if (account_type != um_user_get_account_type (user)) { + um_user_set_account_type (user, account_type); + } + + g_object_unref (user); +} + +static void +language_response (GtkDialog *dialog, + gint response_id, + UmUserPanelPrivate *d) +{ + GtkWidget *combo; + UmUser *user; + gchar *lang; + GtkTreeModel *model; + GtkTreeIter iter; + + user = get_selected_user (d); + + combo = get_widget (d, "account-language-combo"); + model = um_editable_combo_get_model (UM_EDITABLE_COMBO (combo)); + + if (response_id == GTK_RESPONSE_OK) { + lang = cc_language_chooser_get_language (GTK_WIDGET (dialog)); + um_user_set_language (user, lang); + } + else { + lang = g_strdup (um_user_get_language (user)); + if (!lang) + lang = cc_common_language_get_current_language (); + } + cc_common_language_get_iter_for_language (model, lang, &iter); + um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (combo), &iter); + g_free (lang); + + gtk_widget_hide (GTK_WIDGET (dialog)); + gtk_widget_set_sensitive (combo, TRUE); + + g_object_unref (user); +} + +static void +language_changed (UmEditableCombo *combo, + UmUserPanelPrivate *d) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *lang; + UmUser *user; + + if (!um_editable_combo_get_active_iter (combo, &iter)) + return; + + user = get_selected_user (d); + + model = um_editable_combo_get_model (combo); + + gtk_tree_model_get (model, &iter, 0, &lang, -1); + if (lang) { + if (g_strcmp0 (lang, um_user_get_language (user)) != 0) { + um_user_set_language (user, lang); + } + g_free (lang); + goto out; + } + + if (d->language_chooser) { + cc_language_chooser_clear_filter (d->language_chooser); + gtk_window_present (GTK_WINDOW (d->language_chooser)); + gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE); + goto out; + } + + d->language_chooser = cc_language_chooser_new (gtk_widget_get_toplevel (d->main_box), FALSE); + + g_signal_connect (d->language_chooser, "response", + G_CALLBACK (language_response), d); + g_signal_connect (d->language_chooser, "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + gdk_window_set_cursor (gtk_widget_get_window (gtk_widget_get_toplevel (d->main_box)), NULL); + gtk_window_present (GTK_WINDOW (d->language_chooser)); + gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE); + +out: + g_object_unref (user); +} + +static void +change_password (GtkButton *button, UmUserPanelPrivate *d) +{ + UmUser *user; + + user = get_selected_user (d); + + um_password_dialog_set_user (d->password_dialog, user); + um_password_dialog_show (d->password_dialog, + GTK_WINDOW (gtk_widget_get_toplevel (d->main_box))); + + g_object_unref (user); +} + +static void +change_fingerprint (GtkButton *button, UmUserPanelPrivate *d) +{ + GtkWidget *label, *label2; + UmUser *user; + + user = get_selected_user (d); + + g_assert (g_strcmp0 (g_get_user_name (), um_user_get_user_name (user)) == 0); + + label = get_widget (d, "account-fingerprint-value-label"); + label2 = get_widget (d, "account-fingerprint-button-label"); + fingerprint_button_clicked (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), label, label2, user); + + g_object_unref (user); +} + +static gint +sort_users (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) +{ + UmUser *ua, *ub; + gint sa, sb; + gint result; + + gtk_tree_model_get (model, a, USER_COL, &ua, SORT_KEY_COL, &sa, -1); + gtk_tree_model_get (model, b, USER_COL, &ub, SORT_KEY_COL, &sb, -1); + + if (sa < sb) { + result = -1; + } + else if (sa > sb) { + result = 1; + } + else { + result = um_user_collate (ua, ub); + } + + if (ua) { + g_object_unref (ua); + } + if (ub) { + g_object_unref (ub); + } + + return result; +} + +static gboolean +dont_select_headings (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean selected, + gpointer data) +{ + GtkTreeIter iter; + gboolean is_user; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, USER_ROW_COL, &is_user, -1); + + return is_user; +} + +static void +users_loaded (UmUserManager *manager, + UmUserPanelPrivate *d) +{ + GSList *list, *l; + UmUser *user; + GtkWidget *dialog; + + if (um_user_manager_no_service (d->um)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), + GTK_DIALOG_MODAL, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_CLOSE, + _("Failed to contact the accounts service")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Please make sure that the AccountService is installed and enabled.")); + g_signal_connect_swapped (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + gtk_widget_show (dialog); + + gtk_widget_set_sensitive (d->main_box, FALSE); + } + + list = um_user_manager_list_users (d->um); + g_debug ("Got %d users\n", g_slist_length (list)); + + g_signal_connect (d->um, "user-changed", G_CALLBACK (user_changed), d); + + for (l = list; l; l = l->next) { + user = l->data; + g_debug ("adding user %s\n", um_user_get_real_name (user)); + user_added (d->um, user, d); + } + g_slist_free (list); + + g_signal_connect (d->um, "user-added", G_CALLBACK (user_added), d); + g_signal_connect (d->um, "user-removed", G_CALLBACK (user_removed), d); +} + +static void +add_unlock_tooltip (GtkWidget *button) +{ + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + /* Translator comments: + * We split the line in 2 here to "make it look good", as there's + * no good way to do this in GTK+ for tooltips. See: + * https://bugzilla.gnome.org/show_bug.cgi?id=657168 */ + setup_tooltip_with_embedded_icon (button, + _("To make changes,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + g_signal_connect (button, "button-release-event", + G_CALLBACK (show_tooltip_now), NULL); +} + +static void +remove_unlock_tooltip (GtkWidget *button) +{ + setup_tooltip_with_embedded_icon (button, NULL, NULL, NULL); + g_signal_handlers_disconnect_by_func (button, + G_CALLBACK (show_tooltip_now), NULL); +} + +static void +on_permission_changed (GPermission *permission, + GParamSpec *pspec, + gpointer data) +{ + UmUserPanelPrivate *d = data; + gboolean is_authorized; + gboolean self_selected; + UmUser *user; + GtkWidget *widget; + + user = get_selected_user (d); + if (!user) { + return; + } + + is_authorized = g_permission_get_allowed (G_PERMISSION (d->permission)); + self_selected = um_user_get_uid (user) == geteuid (); + + widget = get_widget (d, "add-user-toolbutton"); + gtk_widget_set_sensitive (widget, is_authorized); + if (is_authorized) { + setup_tooltip_with_embedded_icon (widget, _("Create a user account"), NULL, NULL); + } + else { + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + setup_tooltip_with_embedded_icon (widget, + _("To create a user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + } + + widget = get_widget (d, "remove-user-toolbutton"); + gtk_widget_set_sensitive (widget, is_authorized && !self_selected); + if (is_authorized) { + setup_tooltip_with_embedded_icon (widget, _("Delete the selected user account"), NULL, NULL); + } + else { + gchar *names[3]; + GIcon *icon; + + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + + setup_tooltip_with_embedded_icon (widget, + _("To delete the selected user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); + } + + if (!um_user_is_local_account (user)) { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), FALSE); + remove_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), FALSE); + remove_unlock_tooltip (get_widget (d, "autologin-switch")); + + } else if (is_authorized && um_user_is_local_account (user)) { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), TRUE); + remove_unlock_tooltip (get_widget (d, "autologin-switch")); + } + else { + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), FALSE); + add_unlock_tooltip (get_widget (d, "account-type-combo")); + gtk_widget_set_sensitive (GTK_WIDGET (get_widget (d, "autologin-switch")), FALSE); + add_unlock_tooltip (get_widget (d, "autologin-switch")); + } + + /* The full name entry: insensitive if remote or not authorized and not self */ + widget = get_widget (d, "full-name-entry"); + if (!um_user_is_local_account (user)) { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), FALSE); + remove_unlock_tooltip (widget); + + } else if (is_authorized || self_selected) { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), TRUE); + remove_unlock_tooltip (widget); + + } else { + cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), FALSE); + add_unlock_tooltip (widget); + } + + if (is_authorized || self_selected) { + gtk_widget_show (get_widget (d, "user-icon-button")); + gtk_widget_hide (get_widget (d, "user-icon-nonbutton")); + + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-language-combo")); + + um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), TRUE); + remove_unlock_tooltip (get_widget (d, "account-password-button")); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 1); + } + else { + gtk_widget_hide (get_widget (d, "user-icon-button")); + gtk_widget_show (get_widget (d, "user-icon-nonbutton")); + + um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), FALSE); + add_unlock_tooltip (get_widget (d, "account-language-combo")); + + um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), FALSE); + add_unlock_tooltip (get_widget (d, "account-password-button")); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 0); + } + + um_password_dialog_set_privileged (d->password_dialog, is_authorized); + + g_object_unref (user); +} + +static gboolean +match_user (GtkTreeModel *model, + gint column, + const gchar *key, + GtkTreeIter *iter, + gpointer search_data) +{ + UmUser *user; + const gchar *name; + gchar *normalized_key = NULL; + gchar *normalized_name = NULL; + gchar *case_normalized_key = NULL; + gchar *case_normalized_name = NULL; + gchar *p; + gboolean result = TRUE; + gint i; + + gtk_tree_model_get (model, iter, USER_COL, &user, -1); + + if (!user) { + goto out; + } + + normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); + if (!normalized_key) { + goto out; + } + + case_normalized_key = g_utf8_casefold (normalized_key, -1); + + for (i = 0; i < 2; i++) { + if (i == 0) { + name = um_user_get_real_name (user); + } + else { + name = um_user_get_user_name (user); + } + g_free (normalized_name); + normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL); + if (normalized_name) { + g_free (case_normalized_name); + case_normalized_name = g_utf8_casefold (normalized_name, -1); + p = strstr (case_normalized_name, case_normalized_key); + + /* poor man's \b */ + if (p == case_normalized_name || (p && p[-1] == ' ')) { + result = FALSE; + break; + } + } + } + + out: + if (user) { + g_object_unref (user); + } + g_free (normalized_key); + g_free (case_normalized_key); + g_free (normalized_name); + g_free (case_normalized_name); + + return result; +} + +static void +autologin_cell_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + UmUserPanelPrivate *d) +{ + gboolean is_autologin; + + gtk_tree_model_get (model, iter, AUTOLOGIN_COL, &is_autologin, -1); + + if (is_autologin) { + g_object_set (cell, "icon-name", "emblem-default-symbolic", NULL); + } else { + g_object_set (cell, "icon-name", NULL, NULL); + } +} + +static void +setup_main_window (UmUserPanelPrivate *d) +{ + GtkWidget *userlist; + GtkTreeModel *model; + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkTreeSelection *selection; + GtkWidget *button; + GtkTreeIter iter; + gint expander_size; + gchar *title; + GIcon *icon; + GError *error = NULL; + gchar *names[3]; + + userlist = get_widget (d, "list-treeview"); + store = gtk_list_store_new (NUM_USER_LIST_COLS, + UM_TYPE_USER, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_INT, + G_TYPE_BOOLEAN); + model = (GtkTreeModel *)store; + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), sort_users, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); + gtk_tree_view_set_model (GTK_TREE_VIEW (userlist), model); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (userlist), USER_COL); + gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (userlist), + match_user, NULL, NULL); + g_object_unref (model); + + g_signal_connect (d->um, "users-loaded", G_CALLBACK (users_loaded), d); + + gtk_widget_style_get (userlist, "expander-size", &expander_size, NULL); + gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (userlist), - (expander_size + 6)); + + title = g_strdup_printf ("%s", _("My Account")); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + TITLE_COL, title, + HEADING_ROW_COL, TRUE, + SORT_KEY_COL, 0, + AUTOLOGIN_COL, FALSE, + -1); + g_free (title); + + title = g_strdup_printf ("%s", _("Other Accounts")); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + TITLE_COL, title, + HEADING_ROW_COL, TRUE, + SORT_KEY_COL, 2, + AUTOLOGIN_COL, FALSE, + -1); + g_free (title); + + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "pixbuf", FACE_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", NAME_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", TITLE_COL); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", HEADING_ROW_COL); + cell = gtk_cell_renderer_pixbuf_new (); + g_object_set (cell, "follow-state", TRUE, NULL); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL); + gtk_tree_view_column_set_cell_data_func (column, + cell, + (GtkTreeCellDataFunc) autologin_cell_data_func, + d, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (userlist), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (userlist)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (selection, "changed", G_CALLBACK (selected_user_changed), d); + gtk_tree_selection_set_select_function (selection, dont_select_headings, NULL, NULL); + + gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (get_widget (d, "list-scrolledwindow")), 300); + gtk_widget_set_size_request (get_widget (d, "list-scrolledwindow"), 200, -1); + + button = get_widget (d, "add-user-toolbutton"); + g_signal_connect (button, "clicked", G_CALLBACK (add_user), d); + + button = get_widget (d, "remove-user-toolbutton"); + g_signal_connect (button, "clicked", G_CALLBACK (delete_user), d); + + button = get_widget (d, "user-icon-nonbutton"); + add_unlock_tooltip (button); + + button = get_widget (d, "full-name-entry"); + g_signal_connect (button, "editing-done", G_CALLBACK (change_name_done), d); + + button = get_widget (d, "account-type-combo"); + g_signal_connect (button, "editing-done", G_CALLBACK (account_type_changed), d); + + button = get_widget (d, "account-password-button"); + g_signal_connect (button, "start-editing", G_CALLBACK (change_password), d); + + button = get_widget (d, "account-language-combo"); + g_signal_connect (button, "editing-done", G_CALLBACK (language_changed), d); + + button = get_widget (d, "autologin-switch"); + g_signal_connect (button, "notify::active", G_CALLBACK (autologin_changed), d); + + button = get_widget (d, "account-fingerprint-button"); + g_signal_connect (button, "clicked", + G_CALLBACK (change_fingerprint), d); + + d->permission = (GPermission *)polkit_permission_new_sync (USER_ACCOUNTS_PERMISSION, NULL, NULL, &error); + if (d->permission != NULL) { + g_signal_connect (d->permission, "notify", + G_CALLBACK (on_permission_changed), d); + on_permission_changed (d->permission, NULL, d); + } else { + g_warning ("Cannot create '%s' permission: %s", USER_ACCOUNTS_PERMISSION, error->message); + g_error_free (error); + } + + button = get_widget (d, "add-user-toolbutton"); + names[0] = "changes-allow-symbolic"; + names[1] = "changes-allow"; + names[2] = NULL; + icon = (GIcon *)g_themed_icon_new_from_names (names, -1); + setup_tooltip_with_embedded_icon (button, + _("To create a user account,\nclick the * icon first"), + "*", + icon); + button = get_widget (d, "remove-user-toolbutton"); + setup_tooltip_with_embedded_icon (button, + _("To delete the selected user account,\nclick the * icon first"), + "*", + icon); + g_object_unref (icon); +} + +static void +um_user_panel_init (UmUserPanel *self) +{ + UmUserPanelPrivate *d; + GError *error; + volatile GType type G_GNUC_UNUSED; + const gchar *filename; + GtkWidget *button; + GtkStyleContext *context; + + d = self->priv = UM_USER_PANEL_PRIVATE (self); + + /* register types that the builder might need */ + type = um_editable_button_get_type (); + type = cc_editable_entry_get_type (); + type = um_editable_combo_get_type (); + + gtk_widget_set_size_request (GTK_WIDGET (self), -1, 350); + + d->builder = gtk_builder_new (); + d->um = um_user_manager_ref_default (); + + filename = UIDIR "/user-accounts-dialog.ui"; + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + filename = "data/user-accounts-dialog.ui"; + } + error = NULL; + if (!gtk_builder_add_from_file (d->builder, filename, &error)) { + g_error ("%s", error->message); + g_error_free (error); + return; + } + + setup_main_window (d); + d->password_dialog = um_password_dialog_new (); + button = get_widget (d, "user-icon-button"); + d->photo_dialog = um_photo_dialog_new (button); + d->main_box = get_widget (d, "accounts-vbox"); + gtk_widget_reparent (d->main_box, GTK_WIDGET (self)); + + context = gtk_widget_get_style_context (get_widget (d, "list-scrolledwindow")); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + context = gtk_widget_get_style_context (get_widget (d, "add-remove-toolbar")); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); +} + +static void +um_user_panel_dispose (GObject *object) +{ + UmUserPanelPrivate *priv = UM_USER_PANEL (object)->priv; + + if (priv->um) { + g_object_unref (priv->um); + priv->um = NULL; + } + if (priv->builder) { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->password_dialog) { + um_password_dialog_free (priv->password_dialog); + priv->password_dialog = NULL; + } + if (priv->photo_dialog) { + um_photo_dialog_free (priv->photo_dialog); + priv->photo_dialog = NULL; + } + if (priv->language_chooser) { + gtk_widget_destroy (priv->language_chooser); + priv->language_chooser = NULL; + } + if (priv->permission) { + g_object_unref (priv->permission); + priv->permission = NULL; + } + G_OBJECT_CLASS (um_user_panel_parent_class)->dispose (object); +} + +static GPermission * +um_user_panel_get_permission (CcPanel *panel) +{ + UmUserPanelPrivate *priv = UM_USER_PANEL (panel)->priv; + + return priv->permission; +} + +static const char * +um_user_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/user-accounts"; + else + return "help:gnome-help/user-accounts"; +} + +static void +um_user_panel_class_init (UmUserPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + object_class->dispose = um_user_panel_dispose; + + panel_class->get_permission = um_user_panel_get_permission; + panel_class->get_help_uri = um_user_panel_get_help_uri; + + g_type_class_add_private (klass, sizeof (UmUserPanelPrivate)); +} + +void +um_user_panel_register (GIOModule *module) +{ + um_user_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + UM_TYPE_USER_PANEL, "user-accounts", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.c gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.c --- gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,748 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "um-utils.h" + +typedef struct { + gchar *text; + gchar *placeholder_str; + GIcon *icon; + gunichar placeholder; + gulong query_id; +} IconShapeData; + +static IconShapeData * +icon_shape_data_new (const gchar *text, + const gchar *placeholder, + GIcon *icon) +{ + IconShapeData *data; + + data = g_new0 (IconShapeData, 1); + + data->text = g_strdup (text); + data->placeholder_str = g_strdup (placeholder); + data->placeholder = g_utf8_get_char_validated (placeholder, -1); + data->icon = g_object_ref (icon); + + return data; +} + +static void +icon_shape_data_free (gpointer user_data) +{ + IconShapeData *data = user_data; + + g_free (data->text); + g_free (data->placeholder_str); + g_object_unref (data->icon); + g_free (data); +} + +static void +icon_shape_renderer (cairo_t *cr, + PangoAttrShape *attr, + gboolean do_path, + gpointer user_data) +{ + IconShapeData *data = user_data; + gdouble x, y; + + cairo_get_current_point (cr, &x, &y); + if (GPOINTER_TO_UINT (attr->data) == data->placeholder) { + gdouble ascent; + gdouble height; + GdkPixbuf *pixbuf; + GtkIconInfo *info; + + ascent = pango_units_to_double (attr->ink_rect.y); + height = pango_units_to_double (attr->ink_rect.height); + info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), + data->icon, + (gint)height, + GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_USE_BUILTIN); + pixbuf = gtk_icon_info_load_icon (info, NULL); + gtk_icon_info_free (info); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_reset_clip (cr); + gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y + ascent); + cairo_paint (cr); + g_object_unref (pixbuf); + } +} + +static PangoAttrList * +create_shape_attr_list_for_layout (PangoLayout *layout, + IconShapeData *data) +{ + PangoAttrList *attrs; + PangoFontMetrics *metrics; + gint ascent, descent; + PangoRectangle ink_rect, logical_rect; + const gchar *p; + const gchar *text; + gint placeholder_len; + + /* Get font metrics and prepare fancy shape size */ + metrics = pango_context_get_metrics (pango_layout_get_context (layout), + pango_layout_get_font_description (layout), + NULL); + ascent = pango_font_metrics_get_ascent (metrics); + descent = pango_font_metrics_get_descent (metrics); + pango_font_metrics_unref (metrics); + + logical_rect.x = 0; + logical_rect.y = - ascent; + logical_rect.width = ascent + descent; + logical_rect.height = ascent + descent; + + ink_rect = logical_rect; + + attrs = pango_attr_list_new (); + text = pango_layout_get_text (layout); + placeholder_len = strlen (data->placeholder_str); + for (p = text; (p = strstr (p, data->placeholder_str)); p += placeholder_len) { + PangoAttribute *attr; + + attr = pango_attr_shape_new_with_data (&ink_rect, + &logical_rect, + GUINT_TO_POINTER (g_utf8_get_char (p)), + NULL, NULL); + + attr->start_index = p - text; + attr->end_index = attr->start_index + placeholder_len; + + pango_attr_list_insert (attrs, attr); + } + + return attrs; +} + +static gboolean +query_unlock_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tooltip, + GtkTooltip *tooltip, + gpointer user_data) +{ + GtkWidget *label; + PangoLayout *layout; + PangoAttrList *attrs; + IconShapeData *data; + + data = g_object_get_data (G_OBJECT (widget), "icon-shape-data"); + label = g_object_get_data (G_OBJECT (widget), "tooltip-label"); + if (label == NULL) { + label = gtk_label_new (data->text); + g_object_ref_sink (label); + g_object_set_data_full (G_OBJECT (widget), + "tooltip-label", label, g_object_unref); + } + + layout = gtk_label_get_layout (GTK_LABEL (label)); + pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout), + icon_shape_renderer, + data, NULL); + + attrs = create_shape_attr_list_for_layout (layout, data); + gtk_label_set_attributes (GTK_LABEL (label), attrs); + pango_attr_list_unref (attrs); + + gtk_tooltip_set_custom (tooltip, label); + + return TRUE; +} + +void +setup_tooltip_with_embedded_icon (GtkWidget *widget, + const gchar *text, + const gchar *placeholder, + GIcon *icon) +{ + IconShapeData *data; + + data = g_object_get_data (G_OBJECT (widget), "icon-shape-data"); + if (data) { + gtk_widget_set_has_tooltip (widget, FALSE); + g_signal_handler_disconnect (widget, data->query_id); + g_object_set_data (G_OBJECT (widget), "icon-shape-data", NULL); + g_object_set_data (G_OBJECT (widget), "tooltip-label", NULL); + } + + if (!placeholder) { + gtk_widget_set_tooltip_text (widget, text); + return; + } + + data = icon_shape_data_new (text, placeholder, icon); + g_object_set_data_full (G_OBJECT (widget), + "icon-shape-data", + data, + icon_shape_data_free); + + gtk_widget_set_has_tooltip (widget, TRUE); + data->query_id = g_signal_connect (widget, "query-tooltip", + G_CALLBACK (query_unlock_tooltip), NULL); + +} + +gboolean +show_tooltip_now (GtkWidget *widget, + GdkEvent *event) +{ + GtkSettings *settings; + gint timeout; + + settings = gtk_widget_get_settings (widget); + + g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL); + g_object_set (settings, "gtk-tooltip-timeout", 1, NULL); + gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget)); + g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL); + + return FALSE; +} + +static gboolean +query_tooltip (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip, + gpointer user_data) +{ + gchar *tip; + + if (GTK_ENTRY_ICON_SECONDARY == gtk_entry_get_icon_at_pos (GTK_ENTRY (widget), x, y)) { + tip = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget), + GTK_ENTRY_ICON_SECONDARY); + gtk_tooltip_set_text (tooltip, tip); + g_free (tip); + + return TRUE; + } + else { + return FALSE; + } +} + +static void +icon_released (GtkEntry *entry, + GtkEntryIconPosition pos, + GdkEvent *event, + gpointer user_data) +{ + GtkSettings *settings; + gint timeout; + + settings = gtk_widget_get_settings (GTK_WIDGET (entry)); + + g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL); + g_object_set (settings, "gtk-tooltip-timeout", 1, NULL); + gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (GTK_WIDGET (entry))); + g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL); +} + + +void +set_entry_validation_error (GtkEntry *entry, + const gchar *text) +{ + g_object_set (entry, "caps-lock-warning", FALSE, NULL); + gtk_entry_set_icon_from_icon_name (entry, + GTK_ENTRY_ICON_SECONDARY, + "dialog-error-symbolic"); + gtk_entry_set_icon_activatable (entry, + GTK_ENTRY_ICON_SECONDARY, + TRUE); + g_signal_connect (entry, "icon-release", + G_CALLBACK (icon_released), FALSE); + g_signal_connect (entry, "query-tooltip", + G_CALLBACK (query_tooltip), NULL); + g_object_set (entry, "has-tooltip", TRUE, NULL); + gtk_entry_set_icon_tooltip_text (entry, + GTK_ENTRY_ICON_SECONDARY, + text); +} + +void +clear_entry_validation_error (GtkEntry *entry) +{ + gboolean warning; + + g_object_get (entry, "caps-lock-warning", &warning, NULL); + + if (warning) + return; + + g_object_set (entry, "has-tooltip", FALSE, NULL); + gtk_entry_set_icon_from_pixbuf (entry, + GTK_ENTRY_ICON_SECONDARY, + NULL); + g_object_set (entry, "caps-lock-warning", TRUE, NULL); +} + +void +popup_menu_below_button (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + GtkWidget *button) +{ + GtkRequisition menu_req; + GtkTextDirection direction; + GtkAllocation allocation; + + gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req); + + direction = gtk_widget_get_direction (button); + + gdk_window_get_origin (gtk_widget_get_window (button), x, y); + gtk_widget_get_allocation (button, &allocation); + *x += allocation.x; + *y += allocation.y + allocation.height; + + if (direction == GTK_TEXT_DIR_LTR) + *x += MAX (allocation.width - menu_req.width, 0); + else if (menu_req.width > allocation.width) + *x -= menu_req.width - allocation.width; + + *push_in = TRUE; +} + +void +rounded_rectangle (cairo_t *cr, + gdouble aspect, + gdouble x, + gdouble y, + gdouble corner_radius, + gdouble width, + gdouble height) +{ + gdouble radius; + gdouble degrees; + + radius = corner_radius / aspect; + degrees = G_PI / 180.0; + + cairo_new_sub_path (cr); + cairo_arc (cr, + x + width - radius, + y + radius, + radius, + -90 * degrees, + 0 * degrees); + cairo_arc (cr, + x + width - radius, + y + height - radius, + radius, + 0 * degrees, + 90 * degrees); + cairo_arc (cr, + x + radius, + y + height - radius, + radius, + 90 * degrees, + 180 * degrees); + cairo_arc (cr, + x + radius, + y + radius, + radius, + 180 * degrees, + 270 * degrees); + cairo_close_path (cr); +} + +void +down_arrow (GtkStyleContext *context, + cairo_t *cr, + gint x, + gint y, + gint width, + gint height) +{ + GtkStateFlags flags; + GdkRGBA fg_color; + GdkRGBA outline_color; + gdouble vertical_overshoot; + gint diameter; + gdouble radius; + gdouble x_double, y_double; + gdouble angle; + gint line_width; + + flags = gtk_style_context_get_state (context); + + gtk_style_context_get_color (context, flags, &fg_color); + gtk_style_context_get_border_color (context, flags, &outline_color); + + line_width = 1; + angle = G_PI / 2; + vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8)); + if (line_width % 2 == 1) + vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5; + else + vertical_overshoot = ceil (vertical_overshoot); + diameter = (gint) MAX (3, width - 2 * vertical_overshoot); + diameter -= (1 - (diameter + line_width) % 2); + radius = diameter / 2.; + x_double = floor ((x + width / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.; + + y_double = (y + height / 2) - 0.5; + + cairo_save (cr); + + cairo_translate (cr, x_double, y_double); + cairo_rotate (cr, angle); + + cairo_move_to (cr, - radius / 2., - radius); + cairo_line_to (cr, radius / 2., 0); + cairo_line_to (cr, - radius / 2., radius); + + cairo_close_path (cr); + + cairo_set_line_width (cr, line_width); + + gdk_cairo_set_source_rgba (cr, &fg_color); + + cairo_fill_preserve (cr); + + gdk_cairo_set_source_rgba (cr, &outline_color); + cairo_stroke (cr); + + cairo_restore (cr); +} + + +#define MAXNAMELEN (UT_NAMESIZE - 1) + +static gboolean +is_username_used (const gchar *username) +{ + struct passwd *pwent; + + if (username == NULL || username[0] == '\0') { + return FALSE; + } + + pwent = getpwnam (username); + + return pwent != NULL; +} + +gboolean +is_valid_name (const gchar *name) +{ + gboolean valid; + + valid = (strlen (name) > 0); + + return valid; +} + +gboolean +is_valid_username (const gchar *username, gchar **tip) +{ + gboolean empty; + gboolean in_use; + gboolean too_long; + gboolean valid; + const gchar *c; + + if (username == NULL || username[0] == '\0') { + empty = TRUE; + in_use = FALSE; + too_long = FALSE; + } else { + empty = FALSE; + in_use = is_username_used (username); + too_long = strlen (username) > MAXNAMELEN; + } + valid = TRUE; + + if (!in_use && !empty && !too_long) { + /* First char must be a letter, and it must only composed + * of ASCII letters, digits, and a '.', '-', '_' + */ + for (c = username; *c; c++) { + if (! ((*c >= 'a' && *c <= 'z') || + (*c >= 'A' && *c <= 'Z') || + (*c >= '0' && *c <= '9') || + (*c == '_') || (*c == '.') || + (*c == '-' && c != username))) + valid = FALSE; + } + } + + valid = !empty && !in_use && !too_long && valid; + + if (!empty && (in_use || too_long || !valid)) { + if (in_use) { + *tip = g_strdup_printf (_("A user with the username '%s' already exists"), + username); + } + else if (too_long) { + *tip = g_strdup_printf (_("The username is too long")); + } + else if (username[0] == '-') { + *tip = g_strdup (_("The username cannot start with a '-'")); + } + else { + *tip = g_strdup (_("The username must only consist of:\n" + " \xe2\x9e\xa3 letters from the English alphabet\n" + " \xe2\x9e\xa3 digits\n" + " \xe2\x9e\xa3 any of the characters '.', '-' and '_'")); + } + } + else { + *tip = NULL; + } + + return valid; +} + +void +generate_username_choices (const gchar *name, + GtkListStore *store) +{ + gboolean in_use; + char *lc_name, *ascii_name, *stripped_name; + char **words1; + char **words2 = NULL; + char **w1, **w2; + char *c; + char *unicode_fallback = "?"; + GString *first_word, *last_word; + GString *item0, *item1, *item2, *item3, *item4; + int len; + int nwords1, nwords2, i; + GHashTable *items; + GtkTreeIter iter; + + gtk_list_store_clear (store); + + ascii_name = g_convert_with_fallback (name, -1, "ASCII//TRANSLIT", "UTF-8", + unicode_fallback, NULL, NULL, NULL); + + lc_name = g_ascii_strdown (ascii_name, -1); + + /* Remove all non ASCII alphanumeric chars from the name, + * apart from the few allowed symbols. + * + * We do remove '.', even though it is usually allowed, + * since it often comes in via an abbreviated middle name, + * and the dot looks just wrong in the proposals then. + */ + stripped_name = g_strnfill (strlen (lc_name) + 1, '\0'); + i = 0; + for (c = lc_name; *c; c++) { + if (!(g_ascii_isdigit (*c) || g_ascii_islower (*c) || + *c == ' ' || *c == '-' || *c == '_' || + /* used to track invalid words, removed below */ + *c == '?') ) + continue; + + stripped_name[i] = *c; + i++; + } + + if (strlen (stripped_name) == 0) { + g_free (ascii_name); + g_free (lc_name); + g_free (stripped_name); + return; + } + + /* we split name on spaces, and then on dashes, so that we can treat + * words linked with dashes the same way, i.e. both fully shown, or + * both abbreviated + */ + words1 = g_strsplit_set (stripped_name, " ", -1); + len = g_strv_length (words1); + + /* The default item is a concatenation of all words without ? */ + item0 = g_string_sized_new (strlen (stripped_name)); + + g_free (ascii_name); + g_free (lc_name); + g_free (stripped_name); + + /* Concatenate the whole first word with the first letter of each + * word (item1), and the last word with the first letter of each + * word (item2). item3 and item4 are symmetrical respectively to + * item1 and item2. + * + * Constant 5 is the max reasonable number of words we may get when + * splitting on dashes, since we can't guess it at this point, + * and reallocating would be too bad. + */ + item1 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5); + item3 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5); + + item2 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5); + item4 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5); + + /* again, guess at the max size of names */ + first_word = g_string_sized_new (20); + last_word = g_string_sized_new (20); + + nwords1 = 0; + nwords2 = 0; + for (w1 = words1; *w1; w1++) { + if (strlen (*w1) == 0) + continue; + + /* skip words with string '?', most likely resulting + * from failed transliteration to ASCII + */ + if (strstr (*w1, unicode_fallback) != NULL) + continue; + + nwords1++; /* count real words, excluding empty string */ + + item0 = g_string_append (item0, *w1); + + words2 = g_strsplit_set (*w1, "-", -1); + /* reset last word if a new non-empty word has been found */ + if (strlen (*words2) > 0) + last_word = g_string_set_size (last_word, 0); + + for (w2 = words2; *w2; w2++) { + if (strlen (*w2) == 0) + continue; + + nwords2++; + + /* part of the first "toplevel" real word */ + if (nwords1 == 1) { + item1 = g_string_append (item1, *w2); + first_word = g_string_append (first_word, *w2); + } + else { + item1 = g_string_append_unichar (item1, + g_utf8_get_char (*w2)); + item3 = g_string_append_unichar (item3, + g_utf8_get_char (*w2)); + } + + /* not part of the last "toplevel" word */ + if (w1 != words1 + len - 1) { + item2 = g_string_append_unichar (item2, + g_utf8_get_char (*w2)); + item4 = g_string_append_unichar (item4, + g_utf8_get_char (*w2)); + } + + /* always save current word so that we have it if last one reveals empty */ + last_word = g_string_append (last_word, *w2); + } + + g_strfreev (words2); + } + item2 = g_string_append (item2, last_word->str); + item3 = g_string_append (item3, first_word->str); + item4 = g_string_prepend (item4, last_word->str); + + items = g_hash_table_new (g_str_hash, g_str_equal); + + in_use = is_username_used (item0->str); + if (!in_use && !g_ascii_isdigit (item0->str[0])) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item0->str, -1); + g_hash_table_insert (items, item0->str, item0->str); + } + + in_use = is_username_used (item1->str); + if (nwords2 > 0 && !in_use && !g_ascii_isdigit (item1->str[0])) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item1->str, -1); + g_hash_table_insert (items, item1->str, item1->str); + } + + /* if there's only one word, would be the same as item1 */ + if (nwords2 > 1) { + /* add other items */ + in_use = is_username_used (item2->str); + if (!in_use && !g_ascii_isdigit (item2->str[0]) && + !g_hash_table_lookup (items, item2->str)) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item2->str, -1); + g_hash_table_insert (items, item2->str, item2->str); + } + + in_use = is_username_used (item3->str); + if (!in_use && !g_ascii_isdigit (item3->str[0]) && + !g_hash_table_lookup (items, item3->str)) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item3->str, -1); + g_hash_table_insert (items, item3->str, item3->str); + } + + in_use = is_username_used (item4->str); + if (!in_use && !g_ascii_isdigit (item4->str[0]) && + !g_hash_table_lookup (items, item4->str)) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item4->str, -1); + g_hash_table_insert (items, item4->str, item4->str); + } + + /* add the last word */ + in_use = is_username_used (last_word->str); + if (!in_use && !g_ascii_isdigit (last_word->str[0]) && + !g_hash_table_lookup (items, last_word->str)) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, last_word->str, -1); + g_hash_table_insert (items, last_word->str, last_word->str); + } + + /* ...and the first one */ + in_use = is_username_used (first_word->str); + if (!in_use && !g_ascii_isdigit (first_word->str[0]) && + !g_hash_table_lookup (items, first_word->str)) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, first_word->str, -1); + g_hash_table_insert (items, first_word->str, first_word->str); + } + } + + g_hash_table_destroy (items); + g_strfreev (words1); + g_string_free (first_word, TRUE); + g_string_free (last_word, TRUE); + g_string_free (item0, TRUE); + g_string_free (item1, TRUE); + g_string_free (item2, TRUE); + g_string_free (item3, TRUE); + g_string_free (item4, TRUE); +} diff -Nru gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.h gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.h --- gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.h 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/55_user_accounts_hide_controls.patch/panels/user-accounts/um-utils.h 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Written by: Matthias Clasen + */ + +#ifndef __UM_UTILS_H__ +#define __UM_UTILS_H__ + +#include + +G_BEGIN_DECLS + +void setup_tooltip_with_embedded_icon (GtkWidget *widget, + const gchar *text, + const gchar *placeholder, + GIcon *icon); +gboolean show_tooltip_now (GtkWidget *widget, + GdkEvent *event); + +void set_entry_validation_error (GtkEntry *entry, + const gchar *text); +void clear_entry_validation_error (GtkEntry *entry); + +void popup_menu_below_button (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + GtkWidget *button); + +void rounded_rectangle (cairo_t *cr, + gdouble aspect, + gdouble x, + gdouble y, + gdouble corner_radius, + gdouble width, + gdouble height); + +void down_arrow (GtkStyleContext *context, + cairo_t *cr, + gint x, + gint y, + gint width, + gint height); + +gboolean is_valid_name (const gchar *name); +gboolean is_valid_username (const gchar *name, + gchar **tip); + +void generate_username_choices (const gchar *name, + GtkListStore *store); + +G_END_DECLS + +#endif diff -Nru gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/cc-info-panel.c gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/cc-info-panel.c --- gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/cc-info-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/cc-info-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2034 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "cc-info-panel.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "hostname-helper.h" +#include "gsd-disk-space-helper.h" + +/* Autorun options */ +#define PREF_MEDIA_AUTORUN_NEVER "autorun-never" +#define PREF_MEDIA_AUTORUN_X_CONTENT_START_APP "autorun-x-content-start-app" +#define PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE "autorun-x-content-ignore" +#define PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER "autorun-x-content-open-folder" + +#define CUSTOM_ITEM_ASK "cc-item-ask" +#define CUSTOM_ITEM_DO_NOTHING "cc-item-do-nothing" +#define CUSTOM_ITEM_OPEN_FOLDER "cc-item-open-folder" + +#define MEDIA_HANDLING_SCHEMA "org.gnome.desktop.media-handling" + +/* Session */ +#define GNOME_SESSION_MANAGER_SCHEMA "org.gnome.desktop.session" +#define KEY_SESSION_NAME "session-name" + +#define WID(w) (GtkWidget *) gtk_builder_get_object (self->priv->builder, w) + +CC_PANEL_REGISTER (CcInfoPanel, cc_info_panel) + +#define INFO_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_INFO_PANEL, CcInfoPanelPrivate)) + +typedef struct { + /* Will be one of the other two below, or "Unknown" */ + const char *hardware_string; + + char *xorg_vesa_hardware; + char *glx_renderer; +} GraphicsData; + +typedef enum { + PK_NOT_AVAILABLE, + UPDATES_AVAILABLE, + UPDATES_NOT_AVAILABLE, + CHECKING_UPDATES +} UpdatesState; + +typedef struct +{ + const char *content_type; + const char *label; + /* A pattern used to filter supported mime types + when changing preferred applications. NULL + means no other types should be changed */ + const char *extra_type_filter; +} DefaultAppData; + +struct _CcInfoPanelPrivate +{ + GtkBuilder *builder; + char *gnome_version; + char *gnome_distributor; + char *gnome_date; + UpdatesState updates_state; + gboolean is_fallback; + + /* Free space */ + GList *primary_mounts; + guint64 total_bytes; + GCancellable *cancellable; + + /* Media */ + GSettings *media_settings; + GtkWidget *other_application_combo; + + GDBusConnection *session_bus; + GDBusProxy *pk_proxy; + GDBusProxy *pk_transaction_proxy; + GDBusProxy *hostnamed_proxy; + GSettings *session_settings; + + GraphicsData *graphics_data; +}; + +static void get_primary_disc_info_start (CcInfoPanel *self); +static void refresh_update_button (CcInfoPanel *self); + +typedef struct +{ + char *major; + char *minor; + char *micro; + char *distributor; + char *date; + char **current; +} VersionData; + +static void +version_start_element_handler (GMarkupParseContext *ctx, + const char *element_name, + const char **attr_names, + const char **attr_values, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (g_str_equal (element_name, "platform")) + data->current = &data->major; + else if (g_str_equal (element_name, "minor")) + data->current = &data->minor; + else if (g_str_equal (element_name, "micro")) + data->current = &data->micro; + else if (g_str_equal (element_name, "distributor")) + data->current = &data->distributor; + else if (g_str_equal (element_name, "date")) + data->current = &data->date; + else + data->current = NULL; +} + +static void +version_end_element_handler (GMarkupParseContext *ctx, + const char *element_name, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + data->current = NULL; +} + +static void +version_text_handler (GMarkupParseContext *ctx, + const char *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (data->current != NULL) + *data->current = g_strstrip (g_strdup (text)); +} + +static gboolean +load_gnome_version (char **version, + char **distributor, + char **date) +{ + GMarkupParser version_parser = { + version_start_element_handler, + version_end_element_handler, + version_text_handler, + NULL, + NULL, + }; + GError *error; + GMarkupParseContext *ctx; + char *contents; + gsize length; + VersionData *data; + gboolean ret; + + ret = FALSE; + + error = NULL; + if (!g_file_get_contents (DATADIR "/gnome/gnome-version.xml", + &contents, + &length, + &error)) + return FALSE; + + data = g_new0 (VersionData, 1); + ctx = g_markup_parse_context_new (&version_parser, 0, data, NULL); + + if (!g_markup_parse_context_parse (ctx, contents, length, &error)) + { + g_warning ("Invalid version file: '%s'", error->message); + } + else + { + if (version != NULL) + *version = g_strdup_printf ("%s.%s.%s", data->major, data->minor, data->micro); + if (distributor != NULL) + *distributor = g_strdup (data->distributor); + if (date != NULL) + *date = g_strdup (data->date); + + ret = TRUE; + } + + g_markup_parse_context_free (ctx); + g_free (data->major); + g_free (data->minor); + g_free (data->micro); + g_free (data->distributor); + g_free (data->date); + g_free (data); + g_free (contents); + + return ret; +}; + +typedef struct +{ + char *regex; + char *replacement; +} ReplaceStrings; + +static char * +prettify_info (const char *info) +{ + char *pretty; + int i; + static const ReplaceStrings rs[] = { + { "Mesa DRI ", ""}, + { "Intel[(]R[)]", "Intel\302\256"}, + { "Core[(]TM[)]", "Core\342\204\242"}, + { "Atom[(]TM[)]", "Atom\342\204\242"}, + { "Graphics Controller", "Graphics"}, + }; + + pretty = g_markup_escape_text (info, -1); + + for (i = 0; i < G_N_ELEMENTS (rs); i++) + { + GError *error; + GRegex *re; + char *new; + + error = NULL; + + re = g_regex_new (rs[i].regex, 0, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + continue; + } + + new = g_regex_replace_literal (re, + pretty, + -1, + 0, + rs[i].replacement, + 0, + &error); + + g_regex_unref (re); + + if (error != NULL) + { + g_warning ("Error replacing %s: %s", rs[i].regex, error->message); + g_error_free (error); + continue; + } + + g_free (pretty); + pretty = new; + } + + return pretty; +} + +static void +graphics_data_free (GraphicsData *gdata) +{ + g_free (gdata->xorg_vesa_hardware); + g_free (gdata->glx_renderer); + g_slice_free (GraphicsData, gdata); +} + +static char * +get_graphics_data_glx_renderer (void) +{ + GError *error; + GRegex *re; + GMatchInfo *match_info; + char *output; + char *result; + GString *info; + + info = g_string_new (NULL); + + error = NULL; + g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error); + if (error != NULL) + { + g_warning ("Unable to get graphics info: %s", error->message); + g_error_free (error); + return NULL; + } + + re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + goto out; + } + + g_regex_match (re, output, 0, &match_info); + while (g_match_info_matches (match_info)) + { + char *device; + + device = g_match_info_fetch (match_info, 1); + g_string_append_printf (info, "%s ", device); + g_free (device); + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + g_regex_unref (re); + + out: + g_free (output); + result = prettify_info (info->str); + g_string_free (info, TRUE); + + return result; +} + +static char * +get_graphics_data_xorg_vesa_hardware (void) +{ + char *display_num; + char *log_path; + char *log_contents; + gsize log_len; + GError *error = NULL; + GRegex *re; + GMatchInfo *match; + char *result = NULL; + + { + const char *display; + + display = g_getenv ("DISPLAY"); + if (!display) + return NULL; + + re = g_regex_new ("^:([0-9]+)", 0, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, display, 0, &match); + + if (!g_match_info_matches (match)) + { + g_regex_unref (re); + g_match_info_free (match); + return NULL; + } + + display_num = g_match_info_fetch (match, 1); + + g_regex_unref (re); + re = NULL; + g_match_info_free (match); + match = NULL; + } + + log_path = g_strdup_printf ("/var/log/Xorg.%s.log", display_num); + g_free (display_num); + log_contents = NULL; + g_file_get_contents (log_path, &log_contents, &log_len, &error); + g_free (log_path); + if (!log_contents) + return NULL; + + re = g_regex_new ("VESA VBE OEM Product: (.*)$", G_REGEX_MULTILINE, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, log_contents, 0, &match); + if (g_match_info_matches (match)) + { + char *tmp; + char *pretty_tmp; + tmp = g_match_info_fetch (match, 1); + pretty_tmp = prettify_info (tmp); + g_free (tmp); + /* Translators: VESA is an techncial acronym, don't translate it. */ + result = g_strdup_printf (_("VESA: %s"), pretty_tmp); + g_free (pretty_tmp); + } + g_match_info_free (match); + g_regex_unref (re); + + return result; +} + +static GraphicsData * +get_graphics_data (void) +{ + GraphicsData *result; + + result = g_slice_new0 (GraphicsData); + + result->glx_renderer = get_graphics_data_glx_renderer (); + result->xorg_vesa_hardware = get_graphics_data_xorg_vesa_hardware (); + + if (result->xorg_vesa_hardware != NULL) + result->hardware_string = result->xorg_vesa_hardware; + else if (result->glx_renderer != NULL) + result->hardware_string = result->glx_renderer; + else + result->hardware_string = _("Unknown"); + + return result; +} + +static gboolean +get_current_is_fallback (CcInfoPanel *self) +{ + GError *error; + GVariant *reply; + GVariant *reply_str; + gboolean is_fallback; + + error = NULL; + if (!(reply = g_dbus_connection_call_sync (self->priv->session_bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", "org.gnome.SessionManager", "session-name"), + (GVariantType*)"(v)", + 0, + -1, + NULL, &error))) + { + g_warning ("Failed to get fallback mode: %s", error->message); + g_clear_error (&error); + return FALSE; + } + + g_variant_get (reply, "(v)", &reply_str); + is_fallback = g_strcmp0 ("gnome-fallback", g_variant_get_string (reply_str, NULL)) == 0; + g_variant_unref (reply_str); + g_variant_unref (reply); + + return is_fallback; +} + +static void +cc_info_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_dispose (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->pk_proxy != NULL) + { + g_object_unref (priv->pk_proxy); + priv->pk_proxy = NULL; + } + + if (priv->pk_transaction_proxy != NULL) + { + g_object_unref (priv->pk_transaction_proxy); + priv->pk_transaction_proxy = NULL; + } + + if (priv->graphics_data != NULL) + { + graphics_data_free (priv->graphics_data); + priv->graphics_data = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->dispose (object); +} + +static void +cc_info_panel_finalize (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + priv->cancellable = NULL; + } + g_free (priv->gnome_version); + g_free (priv->gnome_date); + g_free (priv->gnome_distributor); + + if (priv->hostnamed_proxy != NULL) + { + g_object_unref (priv->hostnamed_proxy); + priv->hostnamed_proxy = NULL; + } + + if (priv->media_settings != NULL) + { + g_object_unref (priv->media_settings); + priv->media_settings = NULL; + } + + if (priv->session_settings != NULL) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->finalize (object); +} + +static void +cc_info_panel_class_init (CcInfoPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcInfoPanelPrivate)); + + object_class->get_property = cc_info_panel_get_property; + object_class->set_property = cc_info_panel_set_property; + object_class->dispose = cc_info_panel_dispose; + object_class->finalize = cc_info_panel_finalize; +} + +static char * +get_os_type (void) +{ + int bits; + + if (GLIB_SIZEOF_VOID_P == 8) + bits = 64; + else + bits = 32; + + /* translators: This is the type of architecture, for example: + * "64-bit" or "32-bit" */ + return g_strdup_printf (_("%d-bit"), bits); +} + +static void +query_done (GFile *file, + GAsyncResult *res, + CcInfoPanel *self) +{ + GFileInfo *info; + GError *error = NULL; + + self->priv->cancellable = NULL; + info = g_file_query_filesystem_info_finish (file, res, &error); + if (info != NULL) + { + self->priv->total_bytes += g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE); + g_object_unref (info); + } + else + { + char *path; + path = g_file_get_path (file); + g_warning ("Failed to get filesystem free space for '%s': %s", path, error->message); + g_free (path); + g_error_free (error); + } + + /* And onto the next element */ + get_primary_disc_info_start (self); +} + +static void +get_primary_disc_info_start (CcInfoPanel *self) +{ + GUnixMountEntry *mount; + GFile *file; + + if (self->priv->primary_mounts == NULL) + { + char *size; + GtkWidget *widget; + + size = g_format_size (self->priv->total_bytes); + widget = WID ("disk_label"); + gtk_label_set_text (GTK_LABEL (widget), size); + g_free (size); + + return; + } + + mount = self->priv->primary_mounts->data; + self->priv->primary_mounts = g_list_remove (self->priv->primary_mounts, mount); + file = g_file_new_for_path (g_unix_mount_get_mount_path (mount)); + g_unix_mount_free (mount); + + self->priv->cancellable = g_cancellable_new (); + + g_file_query_filesystem_info_async (file, + G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, + 0, + self->priv->cancellable, + (GAsyncReadyCallback) query_done, + self); + g_object_unref (file); +} + +static void +get_primary_disc_info (CcInfoPanel *self) +{ + GList *points; + GList *p; + + points = g_unix_mount_points_get (NULL); + for (p = points; p != NULL; p = p->next) + { + GUnixMountEntry *mount = p->data; + const char *mount_path; + + mount_path = g_unix_mount_get_mount_path (mount); + + if (gsd_should_ignore_unix_mount (mount) || + gsd_is_removable_mount (mount) || + g_str_has_prefix (mount_path, "/media/") || + g_str_has_prefix (mount_path, g_get_home_dir ())) + { + g_unix_mount_free (mount); + continue; + } + + self->priv->primary_mounts = g_list_prepend (self->priv->primary_mounts, mount); + } + g_list_free (points); + + get_primary_disc_info_start (self); +} + +static char * +remove_duplicate_whitespace (const char *old) +{ + char *new; + GRegex *re; + GError *error; + + error = NULL; + re = g_regex_new ("[ \t\n\r]+", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + new = g_regex_replace (re, + old, + -1, + 0, + " ", + 0, + &error); + g_regex_unref (re); + if (new == NULL) + { + g_warning ("Error replacing string: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + + return new; +} + + +static char * +get_cpu_info (const glibtop_sysinfo *info) +{ + GHashTable *counts; + GString *cpu; + char *ret; + GHashTableIter iter; + gpointer key, value; + int i; + int j; + + counts = g_hash_table_new (g_str_hash, g_str_equal); + + /* count duplicates */ + for (i = 0; i != info->ncpu; ++i) + { + const char * const keys[] = { "model name", "cpu" }; + char *model; + int *count; + + model = NULL; + + for (j = 0; model == NULL && j != G_N_ELEMENTS (keys); ++j) + { + model = g_hash_table_lookup (info->cpuinfo[i].values, + keys[j]); + } + + if (model == NULL) + model = _("Unknown model"); + + count = g_hash_table_lookup (counts, model); + if (count == NULL) + g_hash_table_insert (counts, model, GINT_TO_POINTER (1)); + else + g_hash_table_replace (counts, model, GINT_TO_POINTER (GPOINTER_TO_INT (count) + 1)); + } + + cpu = g_string_new (NULL); + g_hash_table_iter_init (&iter, counts); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + char *stripped; + int count; + + count = GPOINTER_TO_INT (value); + stripped = remove_duplicate_whitespace ((const char *)key); + if (count > 1) + g_string_append_printf (cpu, "%s \303\227 %d ", stripped, count); + else + g_string_append_printf (cpu, "%s ", stripped); + g_free (stripped); + } + + g_hash_table_destroy (counts); + + ret = prettify_info (cpu->str); + g_string_free (cpu, TRUE); + + return ret; +} + +static void +on_section_changed (GtkTreeSelection *selection, + gpointer data) +{ + CcInfoPanel *self = CC_INFO_PANEL (data); + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gint *indices; + int index; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + + indices = gtk_tree_path_get_indices (path); + index = indices[0]; + + if (index >= 0) + { + g_object_set (G_OBJECT (WID ("notebook")), + "page", index, NULL); + } + + gtk_tree_path_free (path); +} + +static gboolean +switch_fallback_get_mapping (GValue *value, + GVariant *variant, + gpointer data) +{ + const char *setting; + + setting = g_variant_get_string (variant, NULL); + g_value_set_boolean (value, strcmp (setting, "gnome") != 0); + return TRUE; +} + +static void +toggle_fallback_warning_label (CcInfoPanel *self, + gboolean visible) +{ + GtkWidget *widget; + const char *text; + + widget = WID ("graphics_logout_warning_label"); + + if (self->priv->is_fallback) + text = _("The next login will attempt to use the standard experience."); + else + text = _("The next login will use the fallback mode intended for unsupported graphics hardware."); + + gtk_label_set_text (GTK_LABEL (widget), text); + + if (visible) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); +} + +static GVariant * +switch_fallback_set_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer data) +{ + CcInfoPanel *self = data; + gboolean is_set; + + is_set = g_value_get_boolean (value); + if (is_set != self->priv->is_fallback) + toggle_fallback_warning_label (self, TRUE); + else + toggle_fallback_warning_label (self, FALSE); + + return g_variant_new_string (is_set ? "gnome-fallback" : "gnome"); +} + +static void +info_panel_setup_graphics (CcInfoPanel *self) +{ + GtkWidget *widget; + GtkSwitch *sw; + char *text; + + widget = WID ("graphics_driver_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + self->priv->is_fallback = get_current_is_fallback (self); + if (self->priv->is_fallback) + { + /* translators: The hardware is not able to run GNOME 3's + * shell, so we use the GNOME "Fallback" session */ + text = g_strdup (C_("Experience", "Fallback")); + } + else + { + /* translators: The hardware is able to run GNOME 3's + * shell, also called "Standard" experience */ + text = g_strdup (C_("Experience", "Standard")); + } + widget = WID ("graphics_experience_label"); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("graphics_fallback_switch_box"); + sw = GTK_SWITCH (gtk_switch_new ()); + g_settings_bind_with_mapping (self->priv->session_settings, KEY_SESSION_NAME, + sw, "active", 0, + switch_fallback_get_mapping, + switch_fallback_set_mapping, self, NULL); + gtk_box_pack_start (GTK_BOX (widget), GTK_WIDGET (sw), FALSE, FALSE, 0); + gtk_widget_show_all (GTK_WIDGET (sw)); + widget = WID ("fallback-label"); + gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (sw)); +} + +static void +default_app_changed (GtkAppChooserButton *button, + CcInfoPanel *self) +{ + GAppInfo *info; + GError *error = NULL; + DefaultAppData *app_data; + int i; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (button)); + app_data = g_object_get_data (G_OBJECT (button), "cc-default-app-data"); + + if (g_app_info_set_as_default_for_type (info, app_data->content_type, &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for '%s': %s", + g_app_info_get_name (info), app_data->content_type, error->message); + g_error_free (error); + error = NULL; + } + + if (app_data->extra_type_filter) + { + const char *const *mime_types; + GPatternSpec *pattern; + + pattern = g_pattern_spec_new (app_data->extra_type_filter); + mime_types = g_app_info_get_supported_types (info); + + for (i = 0; mime_types[i]; i++) + { + if (!g_pattern_match_string (pattern, mime_types[i])) + continue; + + if (g_app_info_set_as_default_for_type (info, mime_types[i], &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for secondary " + "content type '%s': %s", + g_app_info_get_name (info), mime_types[i], error->message); + g_error_free (error); + } + } + + g_pattern_spec_free (pattern); + } + + g_object_unref (info); +} + +static void +info_panel_setup_default_app (CcInfoPanel *self, + DefaultAppData *data, + guint left_attach, + guint right_attach, + guint top_attach, + guint bottom_attach) +{ + GtkWidget *button; + GtkWidget *table; + GtkWidget *label; + + table = WID ("default_apps_table"); + + button = gtk_app_chooser_button_new (data->content_type); + g_object_set_data (G_OBJECT (button), "cc-default-app-data", data); + + gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (button), TRUE); + gtk_table_attach (GTK_TABLE (table), button, + left_attach, right_attach, + top_attach, bottom_attach, GTK_FILL, 0, 0, 0); + g_signal_connect (G_OBJECT (button), "changed", + G_CALLBACK (default_app_changed), self); + gtk_widget_show (button); + + label = WID(data->label); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), button); +} + +static DefaultAppData preferred_app_infos[] = { + /* for web, we need to support text/html, + application/xhtml+xml and x-scheme-handler/https, + hence the "*" pattern + */ + { "x-scheme-handler/http", "web-label", "*" }, + { "x-scheme-handler/mailto", "mail-label", NULL }, + { "text/calendar", "calendar-label", NULL }, + { "audio/x-vorbis+ogg", "music-label", "audio/*" }, + { "video/x-ogm+ogg", "video-label", "video/*" }, + { "image/jpeg", "photos-label", "image/*" } +}; + +static void +info_panel_setup_default_apps (CcInfoPanel *self) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(preferred_app_infos); i++) + { + info_panel_setup_default_app (self, &preferred_app_infos[i], + 1, 2, i, i+1); + } +} + +static char ** +remove_elem_from_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + if (g_strcmp0 (v[idx], s) == 0) { + continue; + } + + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static char ** +add_elem_to_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, g_strdup (s)); + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static int +media_panel_g_strv_find (char **strv, + const char *find_me) +{ + guint index; + + g_return_val_if_fail (find_me != NULL, -1); + + for (index = 0; strv[index] != NULL; ++index) { + if (g_strcmp0 (strv[index], find_me) == 0) { + return index; + } + } + + return -1; +} + +static void +autorun_get_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean *pref_start_app, + gboolean *pref_ignore, + gboolean *pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_return_if_fail (pref_start_app != NULL); + g_return_if_fail (pref_ignore != NULL); + g_return_if_fail (pref_open_folder != NULL); + + *pref_start_app = FALSE; + *pref_ignore = FALSE; + *pref_open_folder = FALSE; + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + if (x_content_start_app != NULL) { + *pref_start_app = media_panel_g_strv_find (x_content_start_app, x_content_type) != -1; + } + if (x_content_ignore != NULL) { + *pref_ignore = media_panel_g_strv_find (x_content_ignore, x_content_type) != -1; + } + if (x_content_open_folder != NULL) { + *pref_open_folder = media_panel_g_strv_find (x_content_open_folder, x_content_type) != -1; + } + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + g_strfreev (x_content_open_folder); +} + +static void +autorun_set_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean pref_start_app, + gboolean pref_ignore, + gboolean pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_assert (x_content_type != NULL); + + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + + x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type); + if (pref_start_app) { + x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app); + + x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type); + if (pref_ignore) { + x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore); + + x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type); + if (pref_open_folder) { + x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder); + + g_strfreev (x_content_open_folder); + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + +} + +static void +custom_item_activated_cb (GtkAppChooserButton *button, + const gchar *item, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button)); + + if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, FALSE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, TRUE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) { + autorun_set_preferences (self, content_type, + FALSE, TRUE, FALSE); + } + + g_free (content_type); +} + +static void +combo_box_changed_cb (GtkComboBox *combo_box, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + GAppInfo *info; + gchar *content_type; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + if (info == NULL) + return; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (combo_box)); + autorun_set_preferences (self, content_type, + TRUE, FALSE, FALSE); + g_app_info_set_as_default_for_type (info, content_type, NULL); + + g_object_unref (info); + g_free (content_type); +} + +static void +prepare_combo_box (CcInfoPanel *self, + GtkWidget *combo_box, + const gchar *heading) +{ + GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box); + gboolean pref_ask; + gboolean pref_start_app; + gboolean pref_ignore; + gboolean pref_open_folder; + GAppInfo *info; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser)); + + /* fetch preferences for this content type */ + autorun_get_preferences (self, content_type, + &pref_start_app, &pref_ignore, &pref_open_folder); + pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + /* append the separator only if we have >= 1 apps in the chooser */ + if (info != NULL) { + gtk_app_chooser_button_append_separator (app_chooser); + g_object_unref (info); + } + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK, + _("Ask what to do"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING, + _("Do nothing"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER, + _("Open folder"), + NULL); + + gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE); + gtk_app_chooser_button_set_heading (app_chooser, _(heading)); + + if (pref_ask) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK); + } else if (pref_ignore) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING); + } else if (pref_open_folder) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER); + } + + g_signal_connect (app_chooser, "changed", + G_CALLBACK (combo_box_changed_cb), self); + g_signal_connect (app_chooser, "custom-item-activated", + G_CALLBACK (custom_item_activated_cb), self); + + g_free (content_type); +} + +static void +other_type_combo_box_changed (GtkComboBox *combo_box, + CcInfoPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + char *x_content_type; + GtkWidget *action_container; + GtkWidget *action_label; + + x_content_type = NULL; + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) { + return; + } + + model = gtk_combo_box_get_model (combo_box); + if (model == NULL) { + return; + } + + gtk_tree_model_get (model, &iter, + 1, &x_content_type, + -1); + + action_container = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_container")); + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + } + + self->priv->other_application_combo = gtk_app_chooser_button_new (x_content_type); + gtk_box_pack_start (GTK_BOX (action_container), self->priv->other_application_combo, TRUE, TRUE, 0); + prepare_combo_box (self, self->priv->other_application_combo, NULL); + gtk_widget_show (self->priv->other_application_combo); + + action_label = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_label")); + + gtk_label_set_mnemonic_widget (GTK_LABEL (action_label), self->priv->other_application_combo); + + g_free (x_content_type); +} + +static void +on_extra_options_dialog_response (GtkWidget *dialog, + int response, + CcInfoPanel *self) +{ + gtk_widget_hide (dialog); + + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + self->priv->other_application_combo = NULL; + } +} + +static void +on_extra_options_button_clicked (GtkWidget *button, + CcInfoPanel *self) +{ + GtkWidget *dialog; + GtkWidget *combo_box; + + dialog = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "extra_options_dialog")); + combo_box = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_other_type_combobox")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Other Media")); + g_signal_connect (dialog, + "response", + G_CALLBACK (on_extra_options_dialog_response), + self); + g_signal_connect (dialog, + "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), + NULL); + /* update other_application_combo */ + other_type_combo_box_changed (GTK_COMBO_BOX (combo_box), self); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +info_panel_setup_media (CcInfoPanel *self) +{ + guint n; + GList *l, *content_types; + GtkWidget *other_type_combo_box; + GtkWidget *extras_button; + GtkListStore *other_type_list_store; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkBuilder *builder = self->priv->builder; + + struct { + const gchar *widget_name; + const gchar *content_type; + const gchar *heading; + } const defs[] = { + { "media_audio_cdda_combobox", "x-content/audio-cdda", N_("Select an application for audio CDs") }, + { "media_video_dvd_combobox", "x-content/video-dvd", N_("Select an application for video DVDs") }, + { "media_music_player_combobox", "x-content/audio-player", N_("Select an application to run when a music player is connected") }, + { "media_dcf_combobox", "x-content/image-dcf", N_("Select an application to run when a camera is connected") }, + { "media_software_combobox", "x-content/unix-software", N_("Select an application for software CDs") }, + }; + + struct { + const gchar *content_type; + const gchar *description; + } const other_defs[] = { + /* translators: these strings are duplicates of shared-mime-info + * strings, just here to fix capitalization of the English originals. + * If the shared-mime-info translation works for your language, + * simply leave these untranslated. + */ + { "x-content/audio-dvd", N_("audio DVD") }, + { "x-content/blank-bd", N_("blank Blu-ray disc") }, + { "x-content/blank-cd", N_("blank CD disc") }, + { "x-content/blank-dvd", N_("blank DVD disc") }, + { "x-content/blank-hddvd", N_("blank HD DVD disc") }, + { "x-content/video-bluray", N_("Blu-ray video disc") }, + { "x-content/ebook-reader", N_("e-book reader") }, + { "x-content/video-hddvd", N_("HD DVD video disc") }, + { "x-content/image-picturecd", N_("Picture CD") }, + { "x-content/video-svcd", N_("Super Video CD") }, + { "x-content/video-vcd", N_("Video CD") }, + { "x-content/win32-software", N_("Windows software") }, + { "x-content/software", N_("Software") } + }; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + prepare_combo_box (self, + GTK_WIDGET (gtk_builder_get_object (builder, defs[n].widget_name)), + defs[n].heading); + } + + other_type_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "media_other_type_combobox")); + + other_type_list_store = gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (other_type_list_store), + 1, GTK_SORT_ASCENDING); + + + content_types = g_content_types_get_registered (); + + for (l = content_types; l != NULL; l = l->next) { + char *content_type = l->data; + char *description = NULL; + + if (!g_str_has_prefix (content_type, "x-content/")) + continue; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + if (g_content_type_is_a (content_type, defs[n].content_type)) { + goto skip; + } + } + + for (n = 0; n < G_N_ELEMENTS (other_defs); n++) { + if (strcmp (content_type, other_defs[n].content_type) == 0) { + const gchar *s = other_defs[n].description; + if (s == _(s)) + description = g_content_type_get_description (content_type); + else + description = g_strdup (_(s)); + + break; + } + } + + if (description == NULL) { + g_debug ("Content type '%s' is missing from the info panel", content_type); + description = g_content_type_get_description (content_type); + } + + gtk_list_store_append (other_type_list_store, &iter); + + gtk_list_store_set (other_type_list_store, &iter, + 0, description, + 1, content_type, + -1); + g_free (description); + skip: + ; + } + + g_list_free_full (content_types, g_free); + + gtk_combo_box_set_model (GTK_COMBO_BOX (other_type_combo_box), + GTK_TREE_MODEL (other_type_list_store)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (other_type_combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (other_type_combo_box), renderer, + "text", 0, + NULL); + + g_signal_connect (other_type_combo_box, + "changed", + G_CALLBACK (other_type_combo_box_changed), + self); + + gtk_combo_box_set_active (GTK_COMBO_BOX (other_type_combo_box), 0); + + extras_button = GTK_WIDGET (gtk_builder_get_object (builder, "extra_options_button")); + g_signal_connect (extras_button, + "clicked", + G_CALLBACK (on_extra_options_button_clicked), + self); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + gtk_builder_get_object (self->priv->builder, "media_autorun_never_checkbutton"), + "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_handling_vbox")), + "sensitive", + G_SETTINGS_BIND_INVERT_BOOLEAN); +} + +static void +info_panel_setup_selector (CcInfoPanel *self) +{ + GtkTreeView *view; + GtkListStore *model; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + int section_name_column = 0; + + view = GTK_TREE_VIEW (WID ("overview_treeview")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + + model = gtk_list_store_new (1, G_TYPE_STRING); + gtk_tree_view_set_model (view, GTK_TREE_MODEL (model)); + g_object_unref (model); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_renderer_set_padding (renderer, 4, 4); + g_object_set (renderer, + "width-chars", 20, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes (_("Section"), + renderer, + "text", section_name_column, + NULL); + gtk_tree_view_append_column (view, column); + + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Overview"), + -1); + gtk_tree_selection_select_iter (selection, &iter); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Default Applications"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Removable Media"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Graphics"), + -1); + + g_signal_connect (selection, "changed", + G_CALLBACK (on_section_changed), self); + on_section_changed (selection, self); + + gtk_widget_show_all (GTK_WIDGET (view)); +} + +static char * +get_hostname_property (CcInfoPanel *self, + const char *property) +{ + GVariant *variant; + char *str; + + variant = g_dbus_proxy_get_cached_property (self->priv->hostnamed_proxy, + property); + if (!variant) + { + GError *error = NULL; + GVariant *inner; + + /* Work around systemd-hostname not sending us back + * the property value when changing values */ + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", "org.freedesktop.hostname1", property), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) + { + g_warning ("Failed to get property '%s': %s", property, error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (variant, "(v)", &inner); + str = g_variant_dup_string (inner, NULL); + g_variant_unref (variant); + } + else + { + str = g_variant_dup_string (variant, NULL); + g_variant_unref (variant); + } + + return str; +} + +static char * +info_panel_get_hostname (CcInfoPanel *self) +{ + char *str; + + str = get_hostname_property (self, "PrettyHostname"); + + /* Empty strings means that we need to fallback */ + if (str != NULL && + *str == '\0') + { + g_free (str); + str = get_hostname_property (self, "Hostname"); + } + + return str; +} + +static void +info_panel_set_hostname (CcInfoPanel *self, + const char *text) +{ + char *hostname; + GVariant *variant; + GError *error = NULL; + + g_debug ("Setting PrettyHostname to '%s'", text); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetPrettyHostname", + g_variant_new ("(sb)", text, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set PrettyHostname: %s", error->message); + g_error_free (error); + error = NULL; + } + else + { + g_variant_unref (variant); + } + + /* Set the static hostname */ + hostname = pretty_hostname_to_static (text, FALSE); + g_assert (hostname); + + g_debug ("Setting StaticHostname to '%s'", hostname); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set StaticHostname: %s", error->message); + g_error_free (error); + } + else + { + g_variant_unref (variant); + } + g_free (hostname); +} + +static void +text_changed_cb (GtkEntry *entry, + CcInfoPanel *self) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + info_panel_set_hostname (self, text); +} + +static void +info_panel_setup_hostname (CcInfoPanel *self, + GPermission *permission) +{ + char *str; + GtkWidget *entry; + GError *error = NULL; + + if (permission == NULL) + { + g_debug ("Will not show hostname, hostnamed not installed"); + return; + } + + entry = WID ("name_entry"); + + if (g_permission_get_allowed (permission) != FALSE) + { + g_debug ("Not allowed to change the hostname"); + gtk_widget_set_sensitive (entry, TRUE); + } + + self->priv->hostnamed_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + NULL, + &error); + + /* This could only happen if the policy file was installed + * but not hostnamed, which points to a system bug */ + if (self->priv->hostnamed_proxy == NULL) + { + g_debug ("Couldn't get hostnamed to start, bailing: %s", error->message); + g_error_free (error); + return; + } + + gtk_widget_show (WID ("label4")); + gtk_widget_show (entry); + + str = info_panel_get_hostname (self); + if (str != NULL) + gtk_entry_set_text (GTK_ENTRY (entry), str); + else + gtk_entry_set_text (GTK_ENTRY (entry), ""); + g_free (str); + + g_signal_connect (G_OBJECT (entry), "changed", + G_CALLBACK (text_changed_cb), self); +} + +static void +info_panel_setup_overview (CcInfoPanel *self) +{ + GtkWidget *widget; + gboolean res; + glibtop_mem mem; + const glibtop_sysinfo *info; + char *text; + GPermission *permission; + + permission = polkit_permission_new_sync ("org.freedesktop.hostname1.set-static-hostname", NULL, NULL, NULL); + /* Is hostnamed installed? */ + info_panel_setup_hostname (self, permission); + + res = load_gnome_version (&self->priv->gnome_version, + &self->priv->gnome_distributor, + &self->priv->gnome_date); + if (res) + { + widget = WID ("version_label"); + text = g_strdup_printf (_("Version %s"), self->priv->gnome_version); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); + } + + glibtop_get_mem (&mem); + text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS); + widget = WID ("memory_label"); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + info = glibtop_get_sysinfo (); + + widget = WID ("processor_label"); + text = get_cpu_info (info); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("os_type_label"); + text = get_os_type (); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + get_primary_disc_info (self); + + widget = WID ("graphics_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + widget = WID ("info_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + + refresh_update_button (self); +} + +static void +refresh_update_button (CcInfoPanel *self) +{ + GtkWidget *widget; + + widget = WID ("updates_button"); + if (widget == NULL) + return; + + switch (self->priv->updates_state) + { + case PK_NOT_AVAILABLE: + gtk_widget_set_visible (widget, FALSE); + break; + case UPDATES_AVAILABLE: + gtk_widget_set_sensitive (widget, TRUE); + gtk_button_set_label (GTK_BUTTON (widget), _("Install Updates")); + break; + case UPDATES_NOT_AVAILABLE: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("System Up-To-Date")); + break; + case CHECKING_UPDATES: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("Checking for Updates")); + break; + } +} + +static void +on_pk_transaction_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "Package") == 0) + { + self->priv->updates_state = UPDATES_AVAILABLE; + } + else if (g_strcmp0 (signal_name, "Finished") == 0) + { + if (self->priv->updates_state == CHECKING_UPDATES) + self->priv->updates_state = UPDATES_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "ErrorCode") == 0) + { + self->priv->updates_state = PK_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "Destroy") == 0) + { + g_object_unref (self->priv->pk_transaction_proxy); + self->priv->pk_transaction_proxy = NULL; + } +} + +static void +on_pk_get_updates_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + g_warning ("Error getting PackageKit updates list: %s", error->message); + g_error_free (error); + return; + } +} + +static void +on_pk_get_tid_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + char *tid; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) == FALSE) + g_warning ("Error getting PackageKit transaction ID: %s", error->message); + g_error_free (error); + return; + } + + g_variant_get (result, "(o)", &tid); + + self->priv->pk_transaction_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + tid, + "org.freedesktop.PackageKit.Transaction", + NULL, + NULL); + g_free (tid); + g_variant_unref (result); + + if (self->priv->pk_transaction_proxy == NULL) + { + g_warning ("Unable to get PackageKit transaction proxy object"); + return; + } + + g_signal_connect (self->priv->pk_transaction_proxy, + "g-signal", + G_CALLBACK (on_pk_transaction_signal), + self); + + g_dbus_proxy_call (self->priv->pk_transaction_proxy, + "GetUpdates", + g_variant_new ("(t)", 1), /* PK_FILTER_ENUM_NONE */ + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_updates_ready, + self); +} + +static void +refresh_updates (CcInfoPanel *self) +{ + self->priv->updates_state = CHECKING_UPDATES; + refresh_update_button (self); + + g_assert (self->priv->pk_proxy != NULL); + g_dbus_proxy_call (self->priv->pk_proxy, + "CreateTransaction", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_tid_ready, + self); +} + +static void +on_pk_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "UpdatesChanged") == 0) + { + refresh_updates (self); + } +} + +static void +on_updates_button_clicked (GtkWidget *widget, + CcInfoPanel *self) +{ + GError *error; + error = NULL; + g_spawn_command_line_async ("update-manager", &error); + if (error != NULL) + { + g_warning ("unable to launch Software Updates: %s", error->message); + g_error_free (error); + } +} + +static void +cc_info_panel_init (CcInfoPanel *self) +{ + GError *error = NULL; + GtkWidget *widget; + + self->priv = INFO_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + self->priv->session_settings = g_settings_new (GNOME_SESSION_MANAGER_SCHEMA); + self->priv->media_settings = g_settings_new (MEDIA_HANDLING_SCHEMA); + + self->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + g_assert (self->priv->session_bus); + + self->priv->pk_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + "/org/freedesktop/PackageKit", + "org.freedesktop.PackageKit", + NULL, + NULL); + if (self->priv->pk_proxy == NULL) + { + g_warning ("Unable to get PackageKit proxy object"); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + GVariant *v; + guint32 major, minor, micro; + + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMajor"); + g_variant_get (v, "u", &major); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMinor"); + g_variant_get (v, "u", &minor); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMicro"); + g_variant_get (v, "u", µ); + g_variant_unref (v); + + if (major != 0 || minor != 8) + { + g_warning ("PackageKit version %u.%u.%u not supported", major, minor, micro); + g_clear_object (&self->priv->pk_proxy); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + g_signal_connect (self->priv->pk_proxy, + "g-signal", + G_CALLBACK (on_pk_signal), + self); + refresh_updates (self); + } + } + + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/info.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->graphics_data = get_graphics_data (); + + widget = WID ("updates_button"); + g_signal_connect (widget, "clicked", G_CALLBACK (on_updates_button_clicked), self); + + info_panel_setup_selector (self); + info_panel_setup_overview (self); + info_panel_setup_default_apps (self); + info_panel_setup_media (self); + info_panel_setup_graphics (self); +} + +void +cc_info_panel_register (GIOModule *module) +{ + cc_info_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_INFO_PANEL, + "info", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/info.ui gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/info.ui --- gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/info.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/56_use_ubuntu_info_branding.patch/panels/info/info.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1341 @@ + + + + + False + 10 + False + True + True + dialog + + + True + False + vertical + 2 + + + True + False + end + + + + + + gtk-close + True + True + True + True + True + False + True + + + False + False + 1 + + + + + False + True + end + 0 + + + + + True + False + 5 + vertical + + + True + False + 10 + vertical + + + True + False + 0 + Select how other media should be handled + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + vertical + + + True + False + 6 + 10 + + + True + False + + + 1 + 0 + + + + + True + False + 0 + _Action: + True + + + 0 + 1 + + + + + True + False + + + 1 + 1 + + + + + True + False + 0 + _Type: + True + media_other_type_combobox + + + 0 + 0 + + + + + False + True + 1 + + + + + + + False + True + 1 + + + + + False + True + 0 + + + + + False + True + 1 + + + + + + button1 + + + + False + + + True + False + 10 + vertical + + + True + False + 10 + horizontal + + + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + True + False + 20 + vertical + + + True + False + False + False + + + True + False + 20 + + + True + False + 18 + vertical + + + True + False + GnomeLogoVerticalMedium.svg + + + False + False + 0 + + + + + True + False + Version 3.0 + True + + + + + + False + False + 1 + + + + + True + False + 6 + 3 + 12 + 5 + + + False + True + 1 + Device name + name_entry + + + + + + True + False + 1 + Memory + memory_label + + + + 1 + 2 + + + + + True + False + 1 + Processor + processor_label + + + + 2 + 3 + + + + + True + False + 1 + OS type + os_type_label + + + + 4 + 5 + + + + + True + False + 1 + Disk + disk_label + + + + 5 + 6 + + + + + False + 0 + + False + + + 1 + 2 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 1 + 2 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 2 + 3 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 4 + 5 + + + + + True + False + 0 + Calculating... + True + + + 1 + 2 + 5 + 6 + + + + + True + False + + + + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 5 + 6 + GTK_FILL + + + + + True + False + 1 + Graphics + + + + 3 + 4 + + + + + True + False + + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 3 + 4 + + + + + False + False + 2 + + + + + True + False + end + horizontal + + + + + + Updates Available + True + True + False + True + + + False + True + 1 + + + + + False + False + end + 3 + + + + + + + + + True + False + Overview + + + False + + + + + True + False + center + start + 20 + 10 + vertical + + + True + False + start + start + 6 + 3 + 12 + 12 + + + True + False + 1 + _Web + True + + + + + + True + False + 1 + _Mail + True + + + + 1 + 2 + + + + + True + False + 1 + _Calendar + True + + + + 2 + 3 + + + + + True + False + 1 + M_usic + True + + + + 3 + 4 + + + + + True + False + 1 + _Video + True + + + + 4 + 5 + + + + + True + False + + + + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + True + False + 1 + _Photos + True + + + + 5 + 6 + + + + + True + False + + + + 2 + 3 + 5 + 6 + GTK_FILL + + + + + + + + + + + + + + + + + + + + + + + False + False + 0 + + + + + 1 + + + + + True + False + Default Applications + + + 1 + False + + + + + True + False + horizontal + + + True + False + + + True + False + 10 + 10 + vertical + + + True + False + 10 + start + False + vertical + + + True + False + 10 + vertical + + + True + False + 0 + Select how media should be handled + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + vertical + + + True + False + 5 + 2 + 6 + 6 + + + True + False + 1 + CD _audio + True + media_audio_cdda_combobox + + + + GTK_FILL + + + + + + True + False + 1 + _DVD video + True + media_video_dvd_combobox + + + + 1 + 2 + GTK_FILL + + + + + + True + False + x-content/audio-cdda + + + 1 + 2 + GTK_FILL + + + + + True + False + x-content/video-dvd + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Music player + True + media_music_player_combobox + + + + 2 + 3 + GTK_FILL + + + + + + True + False + x-content/audio-player + + + 1 + 2 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Photos + True + media_dcf_combobox + + + + 3 + 4 + GTK_FILL + + + + + + True + False + x-content/image-dcf + + + 1 + 2 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Software + True + media_software_combobox + + + + 4 + 5 + GTK_FILL + + + + + + True + False + x-content/unix-software + + + 1 + 2 + 4 + 5 + GTK_FILL + GTK_FILL + + + + + False + True + 0 + + + + + True + False + horizontal + + + _Other Media... + True + True + True + False + True + + + False + False + end + 0 + + + + + True + True + 1 + + + + + + + False + True + 1 + + + + + False + True + 0 + + + + + False + False + 0 + + + + + _Never prompt or start programs on media insertion + True + True + False + False + True + 0 + True + end + False + + + False + False + 1 + + + + + + + True + False + 0 + + + + + 2 + + + + + True + False + Removable Media + + + 2 + False + + + + + True + False + 20 + + + True + False + 4 + 2 + 12 + 10 + + + True + False + 1 + Driver + + + + GTK_FILL + GTK_FILL + + + + + True + False + 1 + Experience + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + Forced _Fallback Mode + True + right + + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + False + start + center + horizontal + + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + False + True + 0 + 0 + The next login will use the fallback mode intended for unsupported graphics hardware. + True + True + + + + + + 1 + 2 + 3 + 4 + + + + + True + False + 1 + right + + + 3 + 4 + GTK_FILL + + + + + + + 3 + + + + + True + False + Graphics + graphics_label + + + 3 + False + + + + + True + True + 0 + + + + + True + True + 1 + + + + + True + True + 0 + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/58_hide_gdm_notifications.patch/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/.pc/58_hide_gdm_notifications.patch/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/.pc/58_hide_gdm_notifications.patch/panels/screen/cc-screen-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/58_hide_gdm_notifications.patch/panels/screen/cc-screen-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,564 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "cc-screen-panel.h" + +CC_PANEL_REGISTER (CcScreenPanel, cc_screen_panel) + +#define SCREEN_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SCREEN_PANEL, CcScreenPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +struct _CcScreenPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *session_settings; + GSettings *lockdown_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + gboolean setting_brightness; +}; + + +static void +cc_screen_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_dispose (GObject *object) +{ + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (object)->priv; + + if (priv->lock_settings) + { + g_object_unref (priv->lock_settings); + priv->lock_settings = NULL; + } + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->session_settings) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + G_OBJECT_CLASS (cc_screen_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "lock-delay") == FALSE) + return; +} + +static void +update_lock_screen_sensitivity (CcScreenPanel *self) +{ + GtkWidget *widget; + gboolean locked; + + widget = WID ("screen_lock_main_box"); + locked = g_settings_get_boolean (self->priv->lockdown_settings, "disable-lock-screen"); + gtk_widget_set_sensitive (widget, !locked); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "disable-lock-screen") == FALSE) + return; + + update_lock_screen_sensitivity (panel); +} + +static const char * +cc_screen_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; +} + +static void +cc_screen_panel_class_init (CcScreenPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcScreenPanelPrivate)); + + object_class->get_property = cc_screen_panel_get_property; + object_class->set_property = cc_screen_panel_set_property; + object_class->dispose = cc_screen_panel_dispose; + + panel_class->get_help_uri = cc_screen_panel_get_help_uri; +} + +static void +set_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* not setting, so pay attention to changed signals */ + priv->setting_brightness = FALSE; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + g_printerr ("Error setting brightness: %s\n", error->message); + g_error_free (error); + return; + } +} + +static void +brightness_slider_value_changed_cb (GtkRange *range, gpointer user_data) +{ + guint percentage; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* do not loop */ + if (priv->setting_brightness) + return; + + priv->setting_brightness = TRUE; + + /* push this to g-p-m */ + percentage = (guint) gtk_range_get_value (range); + g_dbus_proxy_call (priv->proxy, + "SetPercentage", + g_variant_new ("(u)", + percentage), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + set_brightness_cb, + user_data); +} + +static void +get_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + guint brightness; + GtkRange *range; + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + /* We got cancelled, so we're probably exiting */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + gtk_widget_hide (WID ("screen_brightness_hscale")); + gtk_widget_hide (WID ("screen_auto_reduce_checkbutton")); + gtk_widget_hide (WID ("brightness-frame")); + g_object_set (G_OBJECT (WID ("turn-off-alignment")), "left-padding", 0, NULL); + + if (error->message && + strstr (error->message, "No backlight devices present") == NULL) + { + g_warning ("Error getting brightness: %s", error->message); + } + g_error_free (error); + return; + } + + /* set the slider */ + g_variant_get (result, + "(u)", + &brightness); + range = GTK_RANGE (WID ("screen_brightness_hscale")); + gtk_range_set_range (range, 0, 100); + gtk_range_set_increments (range, 1, 10); + gtk_range_set_value (range, brightness); + g_signal_connect (range, + "value-changed", + G_CALLBACK (brightness_slider_value_changed_cb), + user_data); + g_variant_unref (result); +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + if (g_strcmp0 (signal_name, "Changed") == 0) + { + /* changed, but ignoring */ + if (self->priv->setting_brightness) + return; + + /* retrieve the value again from g-s-d */ + g_dbus_proxy_call (self->priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + self->priv->cancellable, + get_brightness_cb, + user_data); + } +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (priv->proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* we want to change the bar if the user presses brightness buttons */ + g_signal_connect (priv->proxy, + "g-signal", + G_CALLBACK (on_signal), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + priv->cancellable, + get_brightness_cb, + user_data); +} + +static void +set_idle_delay_from_dpms (CcScreenPanel *self, + int value) +{ + guint off_delay; + + off_delay = 0; + + if (value > 0) + off_delay = (guint) value; + + g_settings_set (self->priv->session_settings, "idle-delay", "u", off_delay); +} + +static void +dpms_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); + g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + + set_idle_delay_from_dpms (self, value); +} + +static void +lock_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint delay; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &delay, + -1); + g_settings_set (self->priv->lock_settings, "lock-delay", "u", delay); +} + +static void +set_dpms_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the AC setting */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +set_lock_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the lock setting */ + g_settings_get (self->priv->lock_settings, "lock-delay", "u", &value); + + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +cc_screen_panel_init (CcScreenPanel *self) +{ + GError *error; + GtkWidget *widget; + + self->priv = SCREEN_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/screen.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->cancellable = g_cancellable_new (); + + /* get initial brightness version */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + self->priv->cancellable, + got_power_proxy_cb, + self); + + self->priv->lock_settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_signal_connect (self->priv->lock_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + self->priv->session_settings = g_settings_new ("org.gnome.desktop.session"); + self->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect (self->priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + /* bind the auto dim checkbox */ + widget = WID ("screen_auto_reduce_checkbutton"); + g_settings_bind (self->priv->gsd_settings, + "idle-dim-battery", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* display off time */ + widget = WID ("screen_brightness_combobox"); + set_dpms_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (dpms_combo_changed_cb), + self); + + /* bind the screen lock checkbox */ + widget = WID ("screen_lock_on_switch"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* lock time */ + widget = WID ("screen_lock_combobox"); + set_lock_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (lock_combo_changed_cb), + self); + + widget = WID ("screen_lock_hbox"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "sensitive", + G_SETTINGS_BIND_GET); + + widget = WID ("show_notifications_check"); + g_settings_bind (self->priv->lock_settings, + "show-notifications", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + update_lock_screen_sensitivity (self); + + widget = WID ("screen_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + g_object_set (self, "valign", GTK_ALIGN_START, NULL); +} + +void +cc_screen_panel_register (GIOModule *module) +{ + cc_screen_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SCREEN_PANEL, + "screen", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/58_ubuntu_icon_views_redesign.patch/shell/gnome-control-center.c gnome-control-center-3.6.3/.pc/58_ubuntu_icon_views_redesign.patch/shell/gnome-control-center.c --- gnome-control-center-3.6.3/.pc/58_ubuntu_icon_views_redesign.patch/shell/gnome-control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/58_ubuntu_icon_views_redesign.patch/shell/gnome-control-center.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1423 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + + +#include "gnome-control-center.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ +#define GMENU_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "cc-panel.h" +#include "cc-shell.h" +#include "cc-shell-category-view.h" +#include "cc-shell-model.h" + +G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) + +#define CONTROL_CENTER_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_CONTROL_CENTER, GnomeControlCenterPrivate)) + +#define W(b,x) GTK_WIDGET (gtk_builder_get_object (b, x)) + +/* Use a fixed width for the shell, since resizing horizontally is more awkward + * for the user than resizing vertically + * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ +#define FIXED_WIDTH 740 +#define FIXED_HEIGHT 636 +#define SMALL_SCREEN_FIXED_HEIGHT 400 + +#define MIN_ICON_VIEW_HEIGHT 300 + +typedef enum { + SMALL_SCREEN_UNSET, + SMALL_SCREEN_TRUE, + SMALL_SCREEN_FALSE +} CcSmallScreen; + +struct _GnomeControlCenterPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GtkWidget *main_vbox; + GtkWidget *scrolled_window; + GtkWidget *search_scrolled; + GtkWidget *current_panel_box; + GtkWidget *current_panel; + char *current_panel_id; + GtkWidget *window; + GtkWidget *search_entry; + GtkWidget *lock_button; + GPtrArray *custom_widgets; + + GMenuTree *menu_tree; + GtkListStore *store; + GHashTable *category_views; + + GtkTreeModel *search_filter; + GtkWidget *search_view; + gchar *filter_string; + + guint32 last_time; + + GIOExtensionPoint *extension_point; + + gchar *default_window_title; + gchar *default_window_icon; + + int monitor_num; + CcSmallScreen small_screen; +}; + +/* Notebook helpers */ +static GtkWidget * +notebook_get_selected_page (GtkWidget *notebook) +{ + int curr; + + curr = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + if (curr == -1) + return NULL; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), curr); +} + +static void +notebook_select_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't select GtkNotebook page %p", page); +} + +static void +notebook_remove_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't find GtkNotebook page to remove %p", page); +} + +static void +notebook_add_page (GtkWidget *notebook, + GtkWidget *page) +{ + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); +} + +static const gchar * +get_icon_name_from_g_icon (GIcon *gicon) +{ + const gchar * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return names[i]; + } + + return NULL; +} + +static gboolean +activate_panel (GnomeControlCenter *shell, + const gchar *id, + const gchar **argv, + const gchar *desktop_file, + const gchar *name, + GIcon *gicon) +{ + GnomeControlCenterPrivate *priv = shell->priv; + GType panel_type = G_TYPE_INVALID; + GList *panels, *l; + GtkWidget *box; + const gchar *icon_name; + + /* check if there is an plugin that implements this panel */ + panels = g_io_extension_point_get_extensions (priv->extension_point); + + if (!desktop_file) + return FALSE; + if (!id) + return FALSE; + + for (l = panels; l != NULL; l = l->next) + { + GIOExtension *extension; + const gchar *name; + + extension = l->data; + + name = g_io_extension_get_name (extension); + + if (!g_strcmp0 (name, id)) + { + panel_type = g_io_extension_get_type (extension); + break; + } + } + + if (panel_type == G_TYPE_INVALID) + { + g_warning ("Could not find the loadable module for panel '%s'", id); + return FALSE; + } + + /* create the panel plugin */ + priv->current_panel = g_object_new (panel_type, "shell", shell, "argv", argv, NULL); + cc_shell_set_active_panel (CC_SHELL (shell), CC_PANEL (priv->current_panel)); + gtk_widget_show (priv->current_panel); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), + cc_panel_get_permission (CC_PANEL (priv->current_panel))); + + box = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (box), 6, 6, 6, 6); + + gtk_container_add (GTK_CONTAINER (box), priv->current_panel); + + gtk_widget_set_name (box, id); + notebook_add_page (priv->notebook, box); + + /* switch to the new panel */ + gtk_widget_show (box); + notebook_select_page (priv->notebook, box); + + /* set the title of the window */ + icon_name = get_icon_name_from_g_icon (gicon); + gtk_window_set_role (GTK_WINDOW (priv->window), id); + gtk_window_set_title (GTK_WINDOW (priv->window), name); + gtk_window_set_default_icon_name (icon_name); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), icon_name); + + priv->current_panel_box = box; + + return TRUE; +} + +static void +_shell_remove_all_custom_widgets (GnomeControlCenterPrivate *priv) +{ + GtkBox *box; + GtkWidget *widget; + guint i; + + /* remove from the header */ + box = GTK_BOX (W (priv->builder, "topright")); + for (i = 0; i < priv->custom_widgets->len; i++) + { + widget = g_ptr_array_index (priv->custom_widgets, i); + gtk_container_remove (GTK_CONTAINER (box), widget); + } + g_ptr_array_set_size (priv->custom_widgets, 0); +} + +static void +shell_show_overview_page (GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + + notebook_select_page (priv->notebook, priv->scrolled_window); + + if (priv->current_panel_box) + notebook_remove_page (priv->notebook, priv->current_panel_box); + priv->current_panel = NULL; + priv->current_panel_box = NULL; + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear the search text */ + g_free (priv->filter_string); + priv->filter_string = g_strdup (""); + gtk_entry_set_text (GTK_ENTRY (priv->search_entry), ""); + gtk_widget_grab_focus (priv->search_entry); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), NULL); + + /* reset window title and icon */ + gtk_window_set_role (GTK_WINDOW (priv->window), NULL); + gtk_window_set_title (GTK_WINDOW (priv->window), priv->default_window_title); + gtk_window_set_default_icon_name (priv->default_window_icon); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), + priv->default_window_icon); + + cc_shell_set_active_panel (CC_SHELL (center), NULL); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); +} + +void +gnome_control_center_set_overview_page (GnomeControlCenter *center) +{ + shell_show_overview_page (center); +} + +static void +item_activated_cb (CcShellCategoryView *view, + gchar *name, + gchar *id, + gchar *desktop_file, + GnomeControlCenter *shell) +{ + GError *err = NULL; + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, &err)) + { + /* TODO: show message to user */ + if (err) + { + g_warning ("Could not active panel \"%s\": %s", id, err->message); + g_error_free (err); + } + } +} + +static gboolean +category_focus_out (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + gtk_icon_view_unselect_all (GTK_ICON_VIEW (view)); + + return FALSE; +} + +static gboolean +category_focus_in (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + GtkTreePath *path; + + if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL)) + { + path = gtk_tree_path_new_from_indices (0, -1); + gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE); + } + + gtk_icon_view_select_path (GTK_ICON_VIEW (view), path); + gtk_tree_path_free (path); + + return FALSE; +} + +static GList * +get_item_views (GnomeControlCenter *shell) +{ + GList *list, *l; + GList *res; + + list = gtk_container_get_children (GTK_CONTAINER (shell->priv->main_vbox)); + res = NULL; + for (l = list; l; l = l->next) + { + if (!CC_IS_SHELL_CATEGORY_VIEW (l->data)) + continue; + res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data))); + } + + g_list_free (list); + + return res; +} + +static gboolean +keynav_failed (GtkIconView *current_view, + GtkDirectionType direction, + GnomeControlCenter *shell) +{ + GList *views, *v; + GtkIconView *new_view; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + gint col, c, dist, d; + GtkTreePath *sel; + gboolean res; + + res = FALSE; + + views = get_item_views (shell); + + for (v = views; v; v = v->next) + { + if (v->data == current_view) + break; + } + + if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL) + { + new_view = v->next->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d < dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL) + { + new_view = v->prev->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d <= dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + g_list_free (views); + + return res; +} + +static gboolean +model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GnomeControlCenterPrivate *priv) +{ + gchar *name, *description; + gchar *needle, *haystack; + gboolean result; + gchar **keywords; + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + COL_DESCRIPTION, &description, + COL_KEYWORDS, &keywords, + -1); + + if (!priv->filter_string || !name) + { + g_free (name); + g_free (description); + g_strfreev (keywords); + return FALSE; + } + + needle = g_utf8_casefold (priv->filter_string, -1); + haystack = g_utf8_casefold (name, -1); + + result = (strstr (haystack, needle) != NULL); + + if (!result && description) + { + gchar *folded; + + folded = g_utf8_casefold (description, -1); + result = (strstr (folded, needle) != NULL); + g_free (folded); + } + + if (!result && keywords) + { + gint i; + gchar *keyword; + + for (i = 0; !result && keywords[i]; i++) + { + keyword = g_utf8_casefold (keywords[i], -1); + result = strstr (keyword, needle) == keyword; + g_free (keyword); + } + } + + g_free (name); + g_free (haystack); + g_free (needle); + g_strfreev (keywords); + + return result; +} + +static gboolean +category_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gchar *filter) +{ + gchar *category; + gboolean result; + + gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1); + + result = (g_strcmp0 (category, filter) == 0); + + g_free (category); + + return result; +} + +static void +search_entry_changed_cb (GtkEntry *entry, + GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + char *str; + + /* if the entry text was set manually (not by the user) */ + if (!g_strcmp0 (priv->filter_string, gtk_entry_get_text (entry))) + return; + + /* Don't re-filter for added trailing or leading spaces */ + str = g_strdup (gtk_entry_get_text (entry)); + g_strstrip (str); + if (!g_strcmp0 (str, priv->filter_string)) + { + g_free (str); + return; + } + + g_free (priv->filter_string); + priv->filter_string = str; + + if (!g_strcmp0 (priv->filter_string, "")) + { + shell_show_overview_page (center); + } + else + { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->search_filter)); + notebook_select_page (priv->notebook, priv->search_scrolled); + } +} + +static gboolean +search_entry_key_press_event_cb (GtkEntry *entry, + GdkEventKey *event, + GnomeControlCenterPrivate *priv) +{ + if (event->keyval == GDK_KEY_Return) + { + GtkTreePath *path; + + path = gtk_tree_path_new_first (); + + priv->last_time = event->time; + + gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->search_view), path); + + gtk_tree_path_free (path); + return TRUE; + } + + if (event->keyval == GDK_KEY_Escape) + { + gtk_entry_set_text (entry, ""); + return TRUE; + } + + return FALSE; +} + +static void +on_search_selection_changed (GtkTreeSelection *selection, + GnomeControlCenter *shell) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + COL_ID, &id, + -1); + + if (id) + cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); + + gtk_tree_selection_unselect_all (selection); + + g_free (id); +} + +static void +setup_search (GnomeControlCenter *shell) +{ + GtkWidget *search_view, *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GnomeControlCenterPrivate *priv = shell->priv; + + g_return_if_fail (priv->store != NULL); + + /* create the search filter */ + priv->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), + NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->search_filter), + (GtkTreeModelFilterVisibleFunc) + model_filter_func, + priv, NULL); + + /* set up the search view */ + priv->search_view = search_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), + GTK_TREE_MODEL (priv->search_filter)); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + "xpad", 15, + "ypad", 10, + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, + "gicon", COL_GICON, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 0, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", COL_NAME, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 15, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Description", renderer, + "text", COL_DESCRIPTION, + NULL); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + priv->search_scrolled = W (priv->builder, "search-scrolled-window"); + gtk_container_add (GTK_CONTAINER (priv->search_scrolled), search_view); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->search_view)), + "changed", + G_CALLBACK (on_search_selection_changed), + shell); + + /* setup the search entry widget */ + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "search-entry"); + priv->search_entry = widget; + priv->filter_string = g_strdup (""); + + g_signal_connect (widget, "changed", G_CALLBACK (search_entry_changed_cb), + shell); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (search_entry_key_press_event_cb), priv); + + gtk_widget_show (priv->search_view); +} + +static void +setup_lock (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + priv->lock_button = W (priv->builder, "lock-button"); +} + +static void +maybe_add_category_view (GnomeControlCenter *shell, + const char *name) +{ + GtkTreeModel *filter; + GtkWidget *categoryview; + + if (g_hash_table_lookup (shell->priv->category_views, name) != NULL) + return; + + if (g_hash_table_size (shell->priv->category_views) > 0) + { + GtkWidget *separator; + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_set_margin_top (separator, 11); + gtk_widget_set_margin_bottom (separator, 10); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), separator, FALSE, FALSE, 0); + gtk_widget_show (separator); + } + + /* create new category view for this category */ + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->priv->store), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + (GtkTreeModelFilterVisibleFunc) category_filter_func, + g_strdup (name), g_free); + + categoryview = cc_shell_category_view_new (name, filter); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), categoryview, FALSE, TRUE, 0); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "desktop-item-activated", + G_CALLBACK (item_activated_cb), shell); + + gtk_widget_show (categoryview); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-in-event", + G_CALLBACK (category_focus_in), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-out-event", + G_CALLBACK (category_focus_out), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "keynav-failed", + G_CALLBACK (keynav_failed), shell); + + g_hash_table_insert (shell->priv->category_views, g_strdup (name), categoryview); +} + +static void +reload_menu (GnomeControlCenter *shell) +{ + GError *error; + GMenuTreeDirectory *d; + GMenuTreeIter *iter; + GMenuTreeItemType next_type; + + error = NULL; + if (!gmenu_tree_load_sync (shell->priv->menu_tree, &error)) + { + g_warning ("Could not load control center menu: %s", error->message); + g_clear_error (&error); + return; + } + + + d = gmenu_tree_get_root_directory (shell->priv->menu_tree); + iter = gmenu_tree_directory_iter (d); + + while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) + { + if (next_type == GMENU_TREE_ITEM_DIRECTORY) + { + GMenuTreeDirectory *subdir; + const gchar *dir_name; + GMenuTreeIter *sub_iter; + GMenuTreeItemType sub_next_type; + + subdir = gmenu_tree_iter_get_directory (iter); + dir_name = gmenu_tree_directory_get_name (subdir); + + maybe_add_category_view (shell, dir_name); + + /* add the items from this category to the model */ + sub_iter = gmenu_tree_directory_iter (subdir); + while ((sub_next_type = gmenu_tree_iter_next (sub_iter)) != GMENU_TREE_ITEM_INVALID) + { + if (sub_next_type == GMENU_TREE_ITEM_ENTRY) + { + GMenuTreeEntry *item = gmenu_tree_iter_get_entry (sub_iter); + cc_shell_model_add_item (CC_SHELL_MODEL (shell->priv->store), + dir_name, + item); + gmenu_tree_item_unref (item); + } + } + + gmenu_tree_iter_unref (sub_iter); + gmenu_tree_item_unref (subdir); + } + } + + gmenu_tree_iter_unref (iter); +} + +static void +on_menu_changed (GMenuTree *monitor, + GnomeControlCenter *shell) +{ + gtk_list_store_clear (shell->priv->store); + reload_menu (shell); +} + +static void +setup_model (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + gtk_widget_set_margin_top (shell->priv->main_vbox, 8); + gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8); + gtk_widget_set_margin_left (shell->priv->main_vbox, 12); + gtk_widget_set_margin_right (shell->priv->main_vbox, 12); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window))); + + priv->store = (GtkListStore *) cc_shell_model_new (); + priv->category_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->menu_tree = gmenu_tree_new_for_path (MENUDIR "/gnomecc.menu", 0); + + reload_menu (shell); + + g_signal_connect (priv->menu_tree, "changed", G_CALLBACK (on_menu_changed), shell); +} + +static void +load_panel_plugins (GnomeControlCenter *shell) +{ + GList *modules; + + /* only allow this function to be run once to prevent modules being loaded + * twice + */ + if (shell->priv->extension_point) + return; + + /* make sure the base type is registered */ + g_type_from_name ("CcPanel"); + + shell->priv->extension_point + = g_io_extension_point_register (CC_SHELL_PANEL_EXTENSION_POINT); + + /* load all the plugins in the panels directory */ + modules = g_io_modules_load_all_in_directory (PANELS_DIR); + g_list_free (modules); + +} + + +static void +home_button_clicked_cb (GtkButton *button, + GnomeControlCenter *shell) +{ + shell_show_overview_page (shell); +} + +static void +notebook_page_notify_cb (GtkNotebook *notebook, + GParamSpec *spec, + GnomeControlCenterPrivate *priv) +{ + int nat_height; + GtkWidget *child; + + child = notebook_get_selected_page (GTK_WIDGET (notebook)); + + /* make sure the home button is shown on all pages except the overview page */ + + if (child == priv->scrolled_window || child == priv->search_scrolled) + { + gtk_widget_hide (W (priv->builder, "home-button")); + gtk_widget_show (W (priv->builder, "search-entry")); + gtk_widget_hide (W (priv->builder, "lock-button")); + + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); + } + else + { + gtk_widget_show (W (priv->builder, "home-button")); + gtk_widget_hide (W (priv->builder, "search-entry")); + /* set the scrolled window small so that it doesn't force + the window to be larger than this panel */ + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } +} + +/* CcShell implementation */ +static void +_shell_embed_widget_in_header (CcShell *shell, + GtkWidget *widget) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkBox *box; + + /* add to header */ + box = GTK_BOX (W (priv->builder, "topright")); + gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + g_ptr_array_add (priv->custom_widgets, g_object_ref (widget)); +} + +/* CcShell implementation */ +static gboolean +_shell_set_active_panel_from_id (CcShell *shell, + const gchar *start_id, + const gchar **argv, + GError **err) +{ + GtkTreeIter iter; + gboolean iter_valid; + gchar *name = NULL; + gchar *desktop = NULL; + GIcon *gicon = NULL; + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkWidget *old_panel; + + /* When loading the same panel again, just set the argv */ + if (g_strcmp0 (priv->current_panel_id, start_id) == 0) + { + g_object_set (G_OBJECT (priv->current_panel), "argv", argv, NULL); + return TRUE; + } + + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + + /* find the details for this item */ + while (iter_valid) + { + gchar *id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + COL_NAME, &name, + COL_DESKTOP_FILE, &desktop, + COL_GICON, &gicon, + COL_ID, &id, + -1); + + if (id && !strcmp (id, start_id)) + { + g_free (id); + break; + } + else + { + g_free (id); + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + name = NULL; + id = NULL; + desktop = NULL; + gicon = NULL; + } + + iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + if (!name) + { + g_warning ("Could not find settings panel \"%s\"", start_id); + } + else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop, + name, gicon) == FALSE) + { + /* Failed to activate the panel for some reason */ + old_panel = priv->current_panel_box; + priv->current_panel_box = NULL; + notebook_select_page (priv->notebook, priv->scrolled_window); + if (old_panel) + notebook_remove_page (priv->notebook, old_panel); + } + else + { + priv->current_panel_id = g_strdup (start_id); + } + + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + return TRUE; +} + +static GtkWidget * +_shell_get_toplevel (CcShell *shell) +{ + return GNOME_CONTROL_CENTER (shell)->priv->window; +} + +/* GObject Implementation */ +static void +gnome_control_center_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_dispose (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + g_free (priv->current_panel_id); + + if (priv->custom_widgets) + { + g_ptr_array_unref (priv->custom_widgets); + priv->custom_widgets = NULL; + } + if (priv->window) + { + gtk_widget_destroy (priv->window); + priv->window = NULL; + + /* destroying the window will destroy its children */ + priv->notebook = NULL; + priv->search_entry = NULL; + priv->search_view = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->store) + { + g_object_unref (priv->store); + priv->store = NULL; + } + + if (priv->search_filter) + { + g_object_unref (priv->search_filter); + priv->search_filter = NULL; + } + + + G_OBJECT_CLASS (gnome_control_center_parent_class)->dispose (object); +} + +static void +gnome_control_center_finalize (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + if (priv->filter_string) + { + g_free (priv->filter_string); + priv->filter_string = NULL; + } + + if (priv->default_window_title) + { + g_free (priv->default_window_title); + priv->default_window_title = NULL; + } + + if (priv->default_window_icon) + { + g_free (priv->default_window_icon); + priv->default_window_icon = NULL; + } + + if (priv->menu_tree) + { + g_signal_handlers_disconnect_by_func (priv->menu_tree, + G_CALLBACK (on_menu_changed), object); + g_object_unref (priv->menu_tree); + } + + if (priv->category_views) + { + g_hash_table_destroy (priv->category_views); + } + + G_OBJECT_CLASS (gnome_control_center_parent_class)->finalize (object); +} + +static void +gnome_control_center_class_init (GnomeControlCenterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcShellClass *shell_class = CC_SHELL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GnomeControlCenterPrivate)); + + object_class->get_property = gnome_control_center_get_property; + object_class->set_property = gnome_control_center_set_property; + object_class->dispose = gnome_control_center_dispose; + object_class->finalize = gnome_control_center_finalize; + + shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id; + shell_class->embed_widget_in_header = _shell_embed_widget_in_header; + shell_class->get_toplevel = _shell_get_toplevel; +} + +static gboolean +window_key_press_event (GtkWidget *win, + GdkEventKey *event, + GnomeControlCenter *self) +{ + GdkKeymap *keymap; + gboolean retval; + GdkModifierType state; + + if (event->state == 0) + return FALSE; + + retval = FALSE; + state = event->state; + keymap = gdk_keymap_get_default (); + gdk_keymap_add_virtual_modifiers (keymap, &state); + state = state & gtk_accelerator_get_default_mod_mask (); + + if (state == GDK_CONTROL_MASK) + { + switch (event->keyval) + { + case GDK_KEY_s: + case GDK_KEY_S: + case GDK_KEY_f: + case GDK_KEY_F: + if (gtk_widget_get_visible (self->priv->search_entry)) + { + gtk_widget_grab_focus (self->priv->search_entry); + retval = TRUE; + } + break; + case GDK_KEY_Q: + case GDK_KEY_q: + g_object_unref (self); + retval = TRUE; + break; + case GDK_KEY_W: + case GDK_KEY_w: + if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) + shell_show_overview_page (self); + retval = TRUE; + break; + } + } + return retval; +} + +static gint +get_monitor_height (GnomeControlCenter *self) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* We cannot use workarea here, as this wouldn't + * be updated when we read it after a monitors-changed signal */ + screen = gtk_widget_get_screen (self->priv->window); + gdk_screen_get_monitor_geometry (screen, self->priv->monitor_num, &rect); + + return rect.height; +} + +static gboolean +update_monitor_number (GnomeControlCenter *self) +{ + gboolean changed = FALSE; + GtkWidget *widget; + GdkScreen *screen; + GdkWindow *window; + int monitor; + + widget = self->priv->window; + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (widget); + monitor = gdk_screen_get_monitor_at_window (screen, window); + if (self->priv->monitor_num != monitor) + { + self->priv->monitor_num = monitor; + changed = TRUE; + } + + return changed; +} + +static CcSmallScreen +is_small (GnomeControlCenter *self) +{ + if (get_monitor_height (self) <= FIXED_HEIGHT) + return SMALL_SCREEN_TRUE; + return SMALL_SCREEN_FALSE; +} + +static void +update_small_screen_settings (GnomeControlCenter *self) +{ + CcSmallScreen small; + + update_monitor_number (self); + small = is_small (self); + + if (small == SMALL_SCREEN_TRUE) + { + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), TRUE); + + if (self->priv->small_screen != small) + gtk_window_maximize (GTK_WINDOW (self->priv->window)); + } + else + { + if (self->priv->small_screen != small) + gtk_window_unmaximize (GTK_WINDOW (self->priv->window)); + + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), FALSE); + } + + self->priv->small_screen = small; + + /* And update the minimum sizes */ + notebook_page_notify_cb (GTK_NOTEBOOK (self->priv->notebook), NULL, self->priv); +} + +static gboolean +main_window_configure_cb (GtkWidget *widget, + GdkEvent *event, + GnomeControlCenter *self) +{ + update_small_screen_settings (self); + return FALSE; +} + +static void +application_set_cb (GObject *object, + GParamSpec *pspec, + GnomeControlCenter *self) +{ + /* update small screen settings now - to avoid visible resizing, we want + * to do it before showing the window, and GtkApplicationWindow cannot be + * realized unless its application property has been set */ + if (gtk_window_get_application (GTK_WINDOW (self->priv->window))) + { + gtk_widget_realize (self->priv->window); + update_small_screen_settings (self); + } +} + +static void +monitors_changed_cb (GdkScreen *screen, + GnomeControlCenter *self) +{ + /* We reset small_screen_set to make sure that the + * window gets maximised if need be, in update_small_screen_settings() */ + self->priv->small_screen = SMALL_SCREEN_UNSET; + update_small_screen_settings (self); +} + +static void +gnome_control_center_init (GnomeControlCenter *self) +{ + GError *err = NULL; + GnomeControlCenterPrivate *priv; + GdkScreen *screen; + + priv = self->priv = CONTROL_CENTER_PRIVATE (self); + +#ifdef HAVE_CHEESE + if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + { + g_critical ("Clutter-GTK init failed"); + return; + } +#endif /* HAVE_CHEESE */ + + priv->monitor_num = -1; + self->priv->small_screen = SMALL_SCREEN_UNSET; + + /* load the user interface */ + priv->builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (priv->builder, UIDIR "/shell.ui", &err)) + { + g_critical ("Could not build interface: %s", err->message); + g_error_free (err); + + return; + } + + /* connect various signals */ + priv->window = W (priv->builder, "main-window"); + gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (priv->window), TRUE); + screen = gtk_widget_get_screen (priv->window); + g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self); + g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self); + g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self); + g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self); + g_signal_connect_after (priv->window, "key_press_event", + G_CALLBACK (window_key_press_event), self); + + priv->notebook = W (priv->builder, "notebook"); + + /* Main scrolled window */ + priv->scrolled_window = W (priv->builder, "scrolledwindow1"); + + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + priv->main_vbox = W (priv->builder, "main-vbox"); + g_signal_connect (priv->notebook, "notify::page", + G_CALLBACK (notebook_page_notify_cb), priv); + + g_signal_connect (gtk_builder_get_object (priv->builder, "home-button"), + "clicked", G_CALLBACK (home_button_clicked_cb), self); + + /* keep a list of custom widgets to unload on panel change */ + priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* load the available settings panels */ + setup_model (self); + + /* load the panels that are implemented as plugins */ + load_panel_plugins (self); + + /* setup search functionality */ + setup_search (self); + + setup_lock (self); + + /* store default window title and name */ + priv->default_window_title = g_strdup (gtk_window_get_title (GTK_WINDOW (priv->window))); + priv->default_window_icon = g_strdup (gtk_window_get_icon_name (GTK_WINDOW (priv->window))); + + notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv); +} + +GnomeControlCenter * +gnome_control_center_new (void) +{ + return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL); +} + +void +gnome_control_center_present (GnomeControlCenter *center) +{ + gtk_window_present (GTK_WINDOW (center->priv->window)); +} + +void +gnome_control_center_show (GnomeControlCenter *center, + GtkApplication *app) +{ + gtk_window_set_application (GTK_WINDOW (center->priv->window), app); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window))); +} diff -Nru gnome-control-center-3.6.3/.pc/59_install_gcm_components_on_demand.patch/panels/color/cc-color-panel.c gnome-control-center-3.6.3/.pc/59_install_gcm_components_on_demand.patch/panels/color/cc-color-panel.c --- gnome-control-center-3.6.3/.pc/59_install_gcm_components_on_demand.patch/panels/color/cc-color-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/59_install_gcm_components_on_demand.patch/panels/color/cc-color-panel.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,2589 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2011 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include +#include + +#include "cc-color-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcColorPanel, cc_color_panel) + +#define COLOR_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_COLOR_PANEL, CcColorPanelPrivate)) + +struct _CcColorPanelPrivate +{ + CdClient *client; + CdDevice *current_device; + CdSensor *sensor; + GCancellable *cancellable; + GDBusProxy *proxy; + GSettings *settings; + GtkBuilder *builder; + GtkTreeStore *list_store_devices; + GtkWidget *main_window; +}; + +enum { + GCM_PREFS_COLUMN_DEVICE_PATH, + GCM_PREFS_COLUMN_SORT, + GCM_PREFS_COLUMN_ICON, + GCM_PREFS_COLUMN_TITLE, + GCM_PREFS_COLUMN_DEVICE, + GCM_PREFS_COLUMN_PROFILE, + GCM_PREFS_COLUMN_STATUS, + GCM_PREFS_COLUMN_STATUS_IMAGE, + GCM_PREFS_COLUMN_TOOLTIP, + GCM_PREFS_COLUMN_RADIO_ACTIVE, + GCM_PREFS_COLUMN_RADIO_VISIBLE, + GCM_PREFS_COLUMN_NUM_COLUMNS +}; + +enum { + GCM_PREFS_COMBO_COLUMN_TEXT, + GCM_PREFS_COMBO_COLUMN_PROFILE, + GCM_PREFS_COMBO_COLUMN_TYPE, + GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS +}; + +typedef enum { + GCM_PREFS_ENTRY_TYPE_PROFILE, + GCM_PREFS_ENTRY_TYPE_IMPORT +} GcmPrefsEntryType; + +#define GCM_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.color" +#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold" +#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold" + +/* max number of devices and profiles to cause auto-expand at startup */ +#define GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED 5 + +static void gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs); + +static void +gcm_prefs_combobox_add_profile (GtkWidget *widget, + CdProfile *profile, + GcmPrefsEntryType entry_type, + GtkTreeIter *iter) +{ + const gchar *id; + GtkTreeModel *model; + GtkTreeIter iter_tmp; + GString *string; + + /* iter is optional */ + if (iter == NULL) + iter = &iter_tmp; + + /* use description */ + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + /* TRANSLATORS: this is where the user can click and import a profile */ + string = g_string_new (_("Other profile…")); + } + else + { + string = g_string_new (cd_profile_get_title (profile)); + + /* any source prefix? */ + id = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile has been auto-generated for this hardware */ + g_string_prepend (string, _("Default: ")); + } +#if CD_CHECK_VERSION(0,1,14) + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile his a standard space like AdobeRGB */ + g_string_prepend (string, _("Colorspace: ")); + } + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile is a test profile */ + g_string_prepend (string, _("Test profile: ")); + } +#endif + } + + /* also add profile */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_list_store_append (GTK_LIST_STORE(model), iter); + gtk_list_store_set (GTK_LIST_STORE(model), iter, + GCM_PREFS_COMBO_COLUMN_TEXT, string->str, + GCM_PREFS_COMBO_COLUMN_PROFILE, profile, + GCM_PREFS_COMBO_COLUMN_TYPE, entry_type, + -1); + g_string_free (string, TRUE); +} + +static void +gcm_prefs_default_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdProfile *profile; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* TODO: check if the profile is already systemwide */ + profile = cd_device_get_default_profile (priv->current_device); + if (profile == NULL) + goto out; + + /* install somewhere out of $HOME */ + ret = cd_profile_install_system_wide_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to set profile system-wide: %s", + error->message); + g_error_free (error); + goto out; + } +out: + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_treeview_popup_menu (CcColorPanel *prefs, GtkWidget *treeview) +{ + GtkWidget *menu, *menuitem; + + menu = gtk_menu_new (); + + /* TRANSLATORS: this is when the profile should be set for all users */ + menuitem = gtk_menu_item_new_with_label (_("Set for all users")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (gcm_prefs_default_cb), + prefs); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + /* TRANSLATORS: this is when the profile should be set for all users */ + menuitem = gtk_menu_item_new_with_label (_("Create virtual device")); + g_signal_connect (menuitem, "activate", + G_CALLBACK (gcm_prefs_device_add_cb), + prefs); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + gtk_widget_show_all (menu); + + /* Note: gdk_event_get_time() accepts a NULL argument */ + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, + gdk_event_get_time (NULL)); +} + +static gboolean +gcm_prefs_treeview_popup_menu_cb (GtkWidget *treeview, CcColorPanel *prefs) +{ + if (prefs->priv->current_device == NULL) + return FALSE; + gcm_prefs_treeview_popup_menu (prefs, treeview); + return TRUE; /* we handled this */ +} + +static GFile * +gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs) +{ + GtkWindow *window; + GtkWidget *dialog; + GFile *file = NULL; + GtkFileFilter *filter; + CcColorPanelPrivate *priv = prefs->priv; + + /* create new dialog */ + window = GTK_WINDOW(gtk_builder_get_object (priv->builder, + "dialog_assign")); + /* TRANSLATORS: an ICC profile is a file containing colorspace data */ + dialog = gtk_file_chooser_dialog_new (_("Select ICC Profile File"), window, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Import"), GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), g_get_home_dir ()); + gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE); + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), FALSE); + + /* setup the filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile"); + + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("Supported ICC profiles")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* setup the all files filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filter, "*"); + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("All files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* did user choose file */ + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog)); + + /* we're done */ + gtk_widget_destroy (dialog); + + /* or NULL for missing */ + return file; +} + +static void +gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + gboolean ret; + GError *error = NULL; + guint xid; + GPtrArray *argv; + CcColorPanelPrivate *priv = prefs->priv; + + /* get xid */ + xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + + /* run with modal set */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-calibrate", NULL)); + g_ptr_array_add (argv, g_strdup ("--device")); + g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + if (!ret) + { + g_warning ("failed to run calibrate: %s", error->message); + g_error_free (error); + } + g_ptr_array_unref (argv); +} + +static void +gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + + /* show ui */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_show (widget); + gtk_window_set_transient_for (GTK_WINDOW (widget), + GTK_WINDOW (priv->main_window)); + + /* clear entries */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_model")); + gtk_entry_set_text (GTK_ENTRY (widget), ""); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_manufacturer")); + gtk_entry_set_text (GTK_ENTRY (widget), ""); +} + +static gboolean +gcm_prefs_is_profile_suitable_for_device (CdProfile *profile, + CdDevice *device) +{ +#if CD_CHECK_VERSION(0,1,14) + const gchar *data_source; +#endif + CdProfileKind profile_kind_tmp; + CdProfileKind profile_kind; + CdColorspace profile_colorspace; + CdColorspace device_colorspace = 0; + gboolean ret = FALSE; + CdDeviceKind device_kind; + + /* not the right colorspace */ + device_colorspace = cd_device_get_colorspace (device); + profile_colorspace = cd_profile_get_colorspace (profile); + if (device_colorspace != profile_colorspace) + goto out; + + /* not the correct kind */ + device_kind = cd_device_get_kind (device); + profile_kind_tmp = cd_profile_get_kind (profile); + profile_kind = cd_device_kind_to_profile_kind (device_kind); + if (profile_kind_tmp != profile_kind) + goto out; + +#if CD_CHECK_VERSION(0,1,14) + /* ignore the colorspace profiles */ + data_source = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + goto out; +#endif + + /* success */ + ret = TRUE; +out: + return ret; +} + +static gint +gcm_prefs_combo_sort_func_cb (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gint type_a, type_b; + gchar *text_a; + gchar *text_b; + gint retval; + + /* get data from model */ + gtk_tree_model_get (model, a, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_a, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_a, + -1); + gtk_tree_model_get (model, b, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_b, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_b, + -1); + + /* prefer normal type profiles over the 'Other Profile...' entry */ + if (type_a < type_b) + retval = -1; + else if (type_a > type_b) + retval = 1; + else + retval = g_strcmp0 (text_a, text_b); + + g_free (text_a); + g_free (text_b); + return retval; +} + +static gboolean +gcm_prefs_combo_set_default_cb (gpointer user_data) +{ + GtkWidget *widget = GTK_WIDGET (user_data); + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + return FALSE; +} + +static gboolean +gcm_prefs_profile_exists_in_array (GPtrArray *array, CdProfile *profile) +{ + CdProfile *profile_tmp; + guint i; + + for (i = 0; i < array->len; i++) + { + profile_tmp = g_ptr_array_index (array, i); + if (cd_profile_equal (profile, profile_tmp)) + return TRUE; + } + return FALSE; +} + +static void +gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs, + GtkWidget *widget, + GPtrArray *profiles) +{ + CdProfile *profile_tmp; + gboolean ret; + GError *error = NULL; + GPtrArray *profile_array = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + guint i; + CcColorPanelPrivate *priv = prefs->priv; + + /* clear existing entries */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + gtk_list_store_clear (GTK_LIST_STORE (model)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + GCM_PREFS_COMBO_COLUMN_TEXT, + GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), + GCM_PREFS_COMBO_COLUMN_TEXT, + gcm_prefs_combo_sort_func_cb, + model, NULL); + + /* get profiles */ + profile_array = cd_client_get_profiles_sync (priv->client, + priv->cancellable, + &error); + if (profile_array == NULL) + { + g_warning ("failed to get profiles: %s", + error->message); + g_error_free (error); + goto out; + } + + /* add profiles of the right kind */ + for (i = 0; i < profile_array->len; i++) + { + profile_tmp = g_ptr_array_index (profile_array, i); + + /* get properties */ + ret = cd_profile_connect_sync (profile_tmp, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + + /* don't add any of the already added profiles */ + if (profiles != NULL) + { + if (gcm_prefs_profile_exists_in_array (profiles, profile_tmp)) + continue; + } + + /* only add correct types */ + ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp, + priv->current_device); + if (!ret) + continue; + +#if CD_CHECK_VERSION(0,1,13) + /* ignore profiles from other user accounts */ + if (!cd_profile_has_access (profile_tmp)) + continue; +#endif + + /* add */ + gcm_prefs_combobox_add_profile (widget, + profile_tmp, + GCM_PREFS_ENTRY_TYPE_PROFILE, + &iter); + } + + /* add a import entry */ +#if CD_CHECK_VERSION(0,1,12) + gcm_prefs_combobox_add_profile (widget, NULL, GCM_PREFS_ENTRY_TYPE_IMPORT, NULL); +#endif + g_idle_add (gcm_prefs_combo_set_default_cb, widget); +out: + if (profile_array != NULL) + g_ptr_array_unref (profile_array); +} + +static void +gcm_prefs_profile_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + const gchar *title; + GPtrArray *profiles; + CcColorPanelPrivate *priv = prefs->priv; + + /* add profiles of the right kind */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + profiles = cd_device_get_profiles (priv->current_device); + gcm_prefs_add_profiles_suitable_for_devices (prefs, widget, profiles); + + /* set the title */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_assign_title")); + switch (cd_device_get_kind (priv->current_device)) { + case CD_DEVICE_KIND_DISPLAY: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Displays"); + break; + case CD_DEVICE_KIND_SCANNER: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Scanners"); + break; + case CD_DEVICE_KIND_PRINTER: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Printers"); + break; + case CD_DEVICE_KIND_CAMERA: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Cameras"); + break; + case CD_DEVICE_KIND_WEBCAM: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */ + title = _("Available Profiles for Webcams"); + break; + default: + /* TRANSLATORS: this is the dialog title in the 'Add profile' UI + * where the device type is not recognised */ + title = _("Available Profiles"); + break; + } + gtk_label_set_label (GTK_LABEL (widget), title); + + /* show the dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_show (widget); + gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (priv->main_window)); + if (profiles != NULL) + g_ptr_array_unref (profiles); +} + +static void +gcm_prefs_profile_remove_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *model; + gboolean ret = FALSE; + CdProfile *profile = NULL; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the selected row */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + goto out; + + /* if the profile is default, then we'll have to make the first profile default */ + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* just remove it, the list store will get ::changed */ + ret = cd_device_remove_profile_sync (priv->current_device, + profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to remove profile: %s", error->message); + g_error_free (error); + goto out; + } +out: + if (profile != NULL) + g_object_unref (profile); + return; +} + +static void +gcm_prefs_make_profile_default_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CdDevice *device = CD_DEVICE (object); + gboolean ret = FALSE; + GError *error = NULL; + + ret = cd_device_make_profile_default_finish (device, + res, + &error); + if (!ret) + { + g_warning ("failed to set default profile on %s: %s", + cd_device_get_id (device), + error->message); + g_error_free (error); + } +} + +static void +gcm_prefs_profile_make_default_internal (CcColorPanel *prefs, + GtkTreeModel *model, + GtkTreeIter *iter_selected) +{ + CdDevice *device; + CdProfile *profile; + CcColorPanelPrivate *priv = prefs->priv; + + /* get currentlt selected item */ + gtk_tree_model_get (model, iter_selected, + GCM_PREFS_COLUMN_DEVICE, &device, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + if (profile == NULL || device == NULL) + goto out; + + /* just set it default */ + g_debug ("setting %s default on %s", + cd_profile_get_id (profile), + cd_device_get_id (device)); + cd_device_make_profile_default (device, + profile, + priv->cancellable, + gcm_prefs_make_profile_default_cb, + prefs); +out: + if (profile != NULL) + g_object_unref (profile); + if (device != NULL) + g_object_unref (device); +} + +static void +gcm_prefs_profile_view_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdProfile *profile = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + gchar *options = NULL; + GPtrArray *argv = NULL; + guint xid; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the selected row */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + g_assert_not_reached (); + + /* get currentlt selected item */ + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* get xid */ + xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window))); + + /* open up gcm-viewer as a info pane */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-viewer", NULL)); + g_ptr_array_add (argv, g_strdup ("--profile")); + g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0, + NULL, NULL, NULL, &error); + if (!ret) + { + g_warning ("failed to run calibrate: %s", error->message); + g_error_free (error); + } + + g_ptr_array_unref (argv); + g_free (options); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_button_assign_cancel_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); +} + +static void +gcm_prefs_button_assign_ok_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeModel *model; + CdProfile *profile = NULL; + gboolean ret = FALSE; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* hide window */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); + + /* get entry */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + goto out; + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, &profile, + -1); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + goto out; + } + + /* just add it, the list store will get ::changed */ + ret = cd_device_add_profile_sync (priv->current_device, + CD_DEVICE_RELATION_HARD, + profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to add: %s", error->message); + g_error_free (error); + goto out; + } + + /* make it default */ + cd_device_make_profile_default (priv->current_device, + profile, + priv->cancellable, + gcm_prefs_make_profile_default_cb, + prefs); +out: + if (profile != NULL) + g_object_unref (profile); +} + +static gboolean +gcm_prefs_profile_delete_event_cb (GtkWidget *widget, + GdkEvent *event, + CcColorPanel *prefs) +{ + gcm_prefs_button_assign_cancel_cb (widget, prefs); + return TRUE; +} + +static void +gcm_prefs_delete_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + gboolean ret = FALSE; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* try to delete device */ + ret = cd_client_delete_device_sync (priv->client, + priv->current_device, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to delete device: %s", error->message); + g_error_free (error); + } +} + +static void +gcm_prefs_treeview_renderer_toggled (GtkCellRendererToggle *cell, + const gchar *path, CcColorPanel *prefs) +{ + gboolean ret; + GtkTreeModel *model; + GtkTreeIter iter; + CcColorPanelPrivate *priv = prefs->priv; + + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_from_string (model, &iter, path); + if (!ret) + return; + gcm_prefs_profile_make_default_internal (prefs, model, &iter); +} + +static void +gcm_prefs_add_devices_columns (CcColorPanel *prefs, + GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + CcColorPanelPrivate *priv = prefs->priv; + + gtk_tree_view_set_headers_visible (treeview, TRUE); + + /* --- column for device image and device title --- */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + /* TRANSLATORS: column for device list */ + gtk_tree_view_column_set_title (column, _("Device")); + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", GCM_PREFS_COLUMN_ICON); + + /* option */ + renderer = gtk_cell_renderer_toggle_new (); + g_signal_connect (renderer, "toggled", + G_CALLBACK (gcm_prefs_treeview_renderer_toggled), prefs); + g_object_set (renderer, "radio", TRUE, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "active", GCM_PREFS_COLUMN_RADIO_ACTIVE); + gtk_tree_view_column_add_attribute (column, renderer, + "visible", GCM_PREFS_COLUMN_RADIO_VISIBLE); + + /* text */ + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", GCM_PREFS_COLUMN_TITLE); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->list_store_devices), + GCM_PREFS_COLUMN_SORT, + GTK_SORT_DESCENDING); + gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column)); + + /* --- column for device status --- */ + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + /* TRANSLATORS: column for device list */ + gtk_tree_view_column_set_title (column, _("Calibration")); + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", GCM_PREFS_COLUMN_STATUS_IMAGE); + + /* text */ + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", GCM_PREFS_COLUMN_STATUS); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column)); + + /* tooltip */ + gtk_tree_view_set_tooltip_column (treeview, + GCM_PREFS_COLUMN_TOOLTIP); +} + +static void +gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *prefs) +{ + gboolean ret = FALSE; + GtkWidget *widget; + const gchar *tooltip; + CdDeviceKind kind; + CcColorPanelPrivate *priv = prefs->priv; + + /* TRANSLATORS: this is when the button is sensitive */ + tooltip = _("Create a color profile for the selected device"); + + /* no device selected */ + if (priv->current_device == NULL) + goto out; + + /* are we a display */ + kind = cd_device_get_kind (priv->current_device); + if (kind == CD_DEVICE_KIND_DISPLAY) + { + + /* find whether we have hardware installed */ + if (priv->sensor == NULL) { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_SCANNER || + kind == CD_DEVICE_KIND_CAMERA || + kind == CD_DEVICE_KIND_WEBCAM) + { + + /* TODO: find out if we can scan using gnome-scan */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_PRINTER) + { + + /* find whether we have hardware installed */ + if (priv->sensor == NULL) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* find whether we have hardware installed */ + ret = cd_sensor_has_cap (priv->sensor, CD_SENSOR_CAP_PRINTER); + if (!ret) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument does not support printer profiling."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The device type is not currently supported."); + } +out: + /* control the tooltip and sensitivity of the button */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + gtk_widget_set_tooltip_text (widget, tooltip); + gtk_widget_set_sensitive (widget, ret); +} + +static void +gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device) +{ + GtkWidget *widget; + CdDeviceMode device_mode; + CcColorPanelPrivate *priv = prefs->priv; + + if (device == NULL) + g_assert_not_reached (); + + /* get current device */ + if (priv->current_device != NULL) + g_object_unref (priv->current_device); + priv->current_device = g_object_ref (device); + + /* we have a new device */ + g_debug ("selected device is: %s", + cd_device_get_id (device)); + + /* make sure selectable */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + gtk_widget_set_sensitive (widget, TRUE); + + /* can we delete this device? */ + device_mode = cd_device_get_mode (priv->current_device); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + gtk_widget_set_visible (widget, device_mode == CD_DEVICE_MODE_VIRTUAL); + + /* can this device calibrate */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static void +gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device) +{ + GtkWidget *widget; + CdDeviceRelation relation; + gchar *s; + CcColorPanelPrivate *priv = prefs->priv; + + /* get profile */ + g_debug ("selected profile = %s", + cd_profile_get_filename (profile)); + + + /* find the profile relationship */ + relation = cd_device_get_profile_relation_sync (device, + profile, + NULL, NULL); + + /* we can only remove hard relationships */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + if (relation == CD_DEVICE_RELATION_HARD) + { + gtk_widget_set_tooltip_text (widget, ""); + gtk_widget_set_sensitive (widget, TRUE); + } + else + { + /* TRANSLATORS: this is when an auto-added profile cannot be removed */ + gtk_widget_set_tooltip_text (widget, _("Cannot remove automatically added profile")); + gtk_widget_set_sensitive (widget, FALSE); + } + + /* allow getting profile info */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + if ((s = g_find_program_in_path ("gcm-viewer"))) + { + gtk_widget_set_sensitive (widget, TRUE); + g_free (s); + } + else + gtk_widget_set_sensitive (widget, FALSE); + + /* hide device specific stuff */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + gtk_widget_set_visible (widget, FALSE); +} + +static void +gcm_prefs_devices_treeview_clicked_cb (GtkTreeSelection *selection, + CcColorPanel *prefs) +{ + GtkTreeModel *model; + GtkTreeIter iter; + CdDevice *device = NULL; + CdProfile *profile = NULL; + GtkWidget *widget; + CcColorPanelPrivate *priv = prefs->priv; + + /* get selection */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE, &device, + GCM_PREFS_COLUMN_PROFILE, &profile, + -1); + + /* device actions */ + if (device != NULL) + gcm_prefs_device_clicked (prefs, device); + if (profile != NULL) + gcm_prefs_profile_clicked (prefs, profile, device); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_default")); + gtk_widget_set_visible (widget, profile != NULL); + if (profile) + gtk_widget_set_sensitive (widget, !cd_profile_get_is_system_wide (profile)); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_add")); + gtk_widget_set_visible (widget, FALSE); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + gtk_widget_set_visible (widget, device != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_add")); + gtk_widget_set_visible (widget, device != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + gtk_widget_set_visible (widget, profile != NULL); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + gtk_widget_set_visible (widget, profile != NULL); + + /* if no buttons then hide toolbar */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbar_devices")); + gtk_widget_set_visible (widget, profile != NULL || device != NULL); + + if (device != NULL) + g_object_unref (device); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_treeview_row_activated_cb (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + CcColorPanel *prefs) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get the iter */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter (model, &iter, path); + if (!ret) + return; + + /* make this profile the default */ + gcm_prefs_profile_make_default_internal (prefs, model, &iter); +} + +static const gchar * +gcm_prefs_device_kind_to_sort (CdDeviceKind kind) +{ + if (kind == CD_DEVICE_KIND_DISPLAY) + return "4"; + if (kind == CD_DEVICE_KIND_SCANNER) + return "3"; + if (kind == CD_DEVICE_KIND_CAMERA) + return "2"; + if (kind == CD_DEVICE_KIND_PRINTER) + return "1"; + return "0"; +} + +static gchar * +gcm_device_get_title (CdDevice *device) +{ + const gchar *model; + const gchar *vendor; + GString *string; + + /* try to get a nice string suitable for display */ + vendor = cd_device_get_vendor (device); + model = cd_device_get_model (device); + string = g_string_new (""); + + if (vendor != NULL && model != NULL) + { + g_string_append_printf (string, "%s - %s", + vendor, model); + goto out; + } + + /* just model */ + if (model != NULL) + { + g_string_append (string, model); + goto out; + } + + /* just vendor */ + if (vendor != NULL) + { + g_string_append (string, vendor); + goto out; + } + + /* fallback to id */ + g_string_append (string, cd_device_get_id (device)); +out: + return g_string_free (string, FALSE); +} + +static void +gcm_prefs_set_combo_simple_text (GtkWidget *combo_box) +{ + GtkCellRenderer *renderer; + GtkListStore *store; + + store = gtk_list_store_new (GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + CD_TYPE_PROFILE, + G_TYPE_UINT); + gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "ellipsize", PANGO_ELLIPSIZE_END, + "wrap-mode", PANGO_WRAP_WORD_CHAR, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", GCM_PREFS_COMBO_COLUMN_TEXT, + NULL); +} + +static void +gcm_prefs_profile_combo_changed_cb (GtkWidget *widget, + CcColorPanel *prefs) +{ + GFile *file = NULL; + GError *error = NULL; + gboolean ret; + CdProfile *profile = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + GcmPrefsEntryType entry_type; + CcColorPanelPrivate *priv = prefs->priv; + + /* no devices */ + if (priv->current_device == NULL) + return; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type, + -1); + + /* import */ + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + file = gcm_prefs_file_chooser_get_icc_profile (prefs); + if (file == NULL) + { + g_warning ("failed to get ICC file"); + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + + /* if we've got no other existing profiles to choose, then + * just close the assign dialog */ + gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type, + -1); + if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT) + { + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + gtk_widget_hide (widget); + } + goto out; + } + +#if CD_CHECK_VERSION(0,1,12) + profile = cd_client_import_profile_sync (priv->client, + file, + priv->cancellable, + &error); + if (profile == NULL) + { + g_warning ("failed to get imported profile: %s", error->message); + g_error_free (error); + goto out; + } +#endif + + /* add to combobox */ + gtk_list_store_append (GTK_LIST_STORE(model), &iter); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, profile, + -1); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter); + } +out: + if (file != NULL) + g_object_unref (file); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_sensor_coldplug (CcColorPanel *prefs) +{ + GPtrArray *sensors; + GError *error = NULL; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* unref old */ + if (priv->sensor != NULL) + { + g_object_unref (priv->sensor); + priv->sensor = NULL; + } + + /* no present */ + sensors = cd_client_get_sensors_sync (priv->client, NULL, &error); + if (sensors == NULL) + { + g_warning ("%s", error->message); + g_error_free (error); + goto out; + } + if (sensors->len == 0) + goto out; + + /* save a copy of the sensor */ + priv->sensor = g_object_ref (g_ptr_array_index (sensors, 0)); + + /* connect to the sensor */ + ret = cd_sensor_connect_sync (priv->sensor, NULL, &error); + if (!ret) + { + g_warning ("%s", error->message); + g_error_free (error); + goto out; + } +out: + if (sensors != NULL) + g_ptr_array_unref (sensors); +} + +static void +gcm_prefs_client_sensor_changed_cb (CdClient *client, + CdSensor *sensor, + CcColorPanel *prefs) +{ + gcm_prefs_sensor_coldplug (prefs); + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static const gchar * +gcm_prefs_device_kind_to_icon_name (CdDeviceKind kind) +{ + switch (kind) { + case CD_DEVICE_KIND_DISPLAY: + return "video-display"; + case CD_DEVICE_KIND_SCANNER: + return "scanner"; + case CD_DEVICE_KIND_PRINTER: + return "printer"; + case CD_DEVICE_KIND_CAMERA: + return "camera-photo"; + case CD_DEVICE_KIND_WEBCAM: + return "camera-web"; + default: + return "image-missing"; + } +} + +static GString * +gcm_prefs_get_profile_age_as_string (CdProfile *profile) +{ + const gchar *id; + gint64 age; + GString *string = NULL; + + if (profile == NULL) + { + /* TRANSLATORS: this is when there is no profile for the device */ + string = g_string_new (_("No profile")); + goto out; + } + + /* don't show details for EDID, colorspace or test profiles */ + id = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0) + goto out; +#if CD_CHECK_VERSION(0,1,14) + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + goto out; + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0) + goto out; +#endif + + /* days */ + age = cd_profile_get_age (profile); + if (age == 0) + { + string = g_string_new (NULL); + goto out; + } + age /= 60 * 60 * 24; + string = g_string_new (""); + + /* approximate years */ + if (age > 365) + { + age /= 365; + g_string_append_printf (string, ngettext ( + "%i year", + "%i years", + age), (guint) age); + goto out; + } + + /* approximate months */ + if (age > 30) + { + age /= 30; + g_string_append_printf (string, ngettext ( + "%i month", + "%i months", + age), (guint) age); + goto out; + } + + /* approximate weeks */ + if (age > 7) + { + age /= 7; + g_string_append_printf (string, ngettext ( + "%i week", + "%i weeks", + age), (guint) age); + goto out; + } + + /* fallback */ + g_string_append_printf (string, _("Less than 1 week")); +out: + return string; +} + +static gchar * +gcm_prefs_get_profile_created_for_sort (CdProfile *profile) +{ + gint64 created; + gchar *string = NULL; + GDateTime *dt = NULL; + + /* get profile age */ + created = cd_profile_get_created (profile); + if (created == 0) + goto out; + dt = g_date_time_new_from_unix_utc (created); + /* note: this is not shown in the UI, just used for sorting */ + string = g_date_time_format (dt, "%Y%m%d"); +out: + if (dt != NULL) + g_date_time_unref (dt); + return string; +} + +static gchar * +gcm_prefs_get_profile_title (CcColorPanel *prefs, CdProfile *profile) +{ + CdColorspace colorspace; + const gchar *title; + gchar *string; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + g_return_val_if_fail (profile != NULL, NULL); + + string = NULL; + + /* get properties */ + ret = cd_profile_connect_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + + /* add profile description */ + title = cd_profile_get_title (profile); + if (title != NULL) + { + string = g_markup_escape_text (title, -1); + goto out; + } + + /* some meta profiles do not have ICC profiles */ + colorspace = cd_profile_get_colorspace (profile); + if (colorspace == CD_COLORSPACE_RGB) + { + string = g_strdup (C_("Colorspace fallback", "Default RGB")); + goto out; + } + if (colorspace == CD_COLORSPACE_CMYK) + { + string = g_strdup (C_("Colorspace fallback", "Default CMYK")); + goto out; + } + if (colorspace == CD_COLORSPACE_GRAY) + { + string = g_strdup (C_("Colorspace fallback", "Default Gray")); + goto out; + } + + /* fall back to ID, ick */ + string = g_strdup (cd_profile_get_id (profile)); +out: + return string; +} + +static void +gcm_prefs_device_remove_profiles_phase1 (CcColorPanel *prefs, GtkTreeIter *parent) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return; + + /* mark to be removed */ + do { + gtk_tree_store_set (priv->list_store_devices, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, NULL, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_device_remove_profiles_phase2 (CcColorPanel *prefs, GtkTreeIter *parent) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gchar *id_tmp; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return; + + /* remove the other elements */ + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (id_tmp == NULL) + ret = gtk_tree_store_remove (priv->list_store_devices, &iter); + else + ret = gtk_tree_model_iter_next (model, &iter); + g_free (id_tmp); + } while (ret); +} + +static GtkTreeIter * +get_iter_for_profile (GtkTreeModel *model, CdProfile *profile, GtkTreeIter *parent) +{ + const gchar *id; + gboolean ret; + GtkTreeIter iter; + CdProfile *profile_tmp; + + /* get first element */ + ret = gtk_tree_model_iter_children (model, &iter, parent); + if (!ret) + return NULL; + + /* remove the other elements */ + id = cd_profile_get_id (profile); + while (ret) + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_PROFILE, &profile_tmp, + -1); + if (g_strcmp0 (id, cd_profile_get_id (profile_tmp)) == 0) + { + g_object_unref (profile_tmp); + return gtk_tree_iter_copy (&iter); + } + g_object_unref (profile_tmp); + ret = gtk_tree_model_iter_next (model, &iter); + } + + return NULL; +} + +static void +gcm_prefs_device_set_model_by_iter (CcColorPanel *prefs, CdDevice *device, GtkTreeIter *iter) +{ + GString *status = NULL; + const gchar *status_image = NULL; + const gchar *tooltip = NULL; + CdProfile *profile = NULL; + gint age; + GPtrArray *profiles = NULL; + CdProfile *profile_tmp; + guint i; + gchar *title_tmp; + GString *date_tmp; + gchar *sort_tmp; + GtkTreeIter iter_tmp; + GtkTreeIter *iter_tmp_p; + guint threshold = 0; + gboolean ret; + GError *error = NULL; + CcColorPanelPrivate *priv = prefs->priv; + + /* set status */ + profile = cd_device_get_default_profile (device); + if (profile == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device is not color managed."); + goto skip; + } + + /* get properties */ + ret = cd_profile_connect_sync (profile, + priv->cancellable, + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + g_error_free (error); + goto out; + } + +#if CD_CHECK_VERSION(0,1,13) + /* ignore profiles from other user accounts */ + if (!cd_profile_has_access (profile)) + { + /* only print the filename if it exists */ + if (cd_profile_get_filename (profile) != NULL) + { + g_warning ("%s is not usable by this user", + cd_profile_get_filename (profile)); + } + else + { + g_warning ("%s is not usable by this user", + cd_profile_get_id (profile)); + } + goto out; + } +#endif + + /* autogenerated printer defaults */ + if (cd_device_get_kind (device) == CD_DEVICE_KIND_PRINTER && + cd_profile_get_filename (profile) == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device is using manufacturing calibrated data."); + goto skip; + } + + /* autogenerated profiles are crap */ + if (cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE && + !cd_profile_get_has_vcgt (profile)) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + tooltip = _("This device does not have a profile suitable for whole-screen color correction."); + goto skip; + } + + /* yay! */ + status = gcm_prefs_get_profile_age_as_string (profile); + if (status == NULL) + { + status = g_string_new (_("Uncalibrated")); + g_string_prepend (status, ""); + g_string_append (status, ""); + } + + /* greater than the calibration threshold for the device type */ + age = cd_profile_get_age (profile); + age /= 60 * 60 * 24; + if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY) + { + g_settings_get (priv->settings, + GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD, + "u", + &threshold); + } + else if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY) + { + g_settings_get (priv->settings, + GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD, + "u", + &threshold); + } + if (threshold > 0 && age > threshold) + { + status_image = "dialog-warning-symbolic"; + tooltip = _("This device has an old profile that may no longer be accurate."); + } +skip: + /* save to store */ + gtk_tree_store_set (priv->list_store_devices, iter, + GCM_PREFS_COLUMN_STATUS, status->str, + GCM_PREFS_COLUMN_STATUS_IMAGE, status_image, + GCM_PREFS_COLUMN_TOOLTIP, tooltip, + -1); + + /* remove old profiles */ + gcm_prefs_device_remove_profiles_phase1 (prefs, iter); + + /* add profiles */ + profiles = cd_device_get_profiles (device); + if (profiles == NULL) + goto out; + for (i = 0; i < profiles->len; i++) + { + profile_tmp = g_ptr_array_index (profiles, i); + title_tmp = gcm_prefs_get_profile_title (prefs, profile_tmp); + + /* get profile age */ + date_tmp = gcm_prefs_get_profile_age_as_string (profile_tmp); + if (date_tmp == NULL) + { + /* TRANSLATORS: this is when the calibration profile age is not + * specified as it has been autogenerated from the hardware */ + date_tmp = g_string_new (_("Not specified")); + g_string_prepend (date_tmp, ""); + g_string_append (date_tmp, ""); + } + sort_tmp = gcm_prefs_get_profile_created_for_sort (profile_tmp); + + /* get an existing profile, or create a new one */ + iter_tmp_p = get_iter_for_profile (GTK_TREE_MODEL (priv->list_store_devices), + profile_tmp, iter); + if (iter_tmp_p == NULL) + gtk_tree_store_append (priv->list_store_devices, &iter_tmp, iter); + + gtk_tree_store_set (priv->list_store_devices, iter_tmp_p ? iter_tmp_p : &iter_tmp, + GCM_PREFS_COLUMN_DEVICE, device, + GCM_PREFS_COLUMN_PROFILE, profile_tmp, + GCM_PREFS_COLUMN_DEVICE_PATH, cd_device_get_object_path (device), + GCM_PREFS_COLUMN_SORT, sort_tmp, + GCM_PREFS_COLUMN_STATUS, date_tmp->str, + GCM_PREFS_COLUMN_TITLE, title_tmp, + GCM_PREFS_COLUMN_RADIO_VISIBLE, TRUE, + GCM_PREFS_COLUMN_RADIO_ACTIVE, i==0, + -1); + if (iter_tmp_p != NULL) + gtk_tree_iter_free (iter_tmp_p); + g_free (title_tmp); + g_free (sort_tmp); + g_string_free (date_tmp, TRUE); + } + + /* remove old profiles that no longer exist */ + gcm_prefs_device_remove_profiles_phase2 (prefs, iter); +out: + if (status != NULL) + g_string_free (status, TRUE); + if (profiles != NULL) + g_ptr_array_unref (profiles); + if (profile != NULL) + g_object_unref (profile); +} + +static void +gcm_prefs_device_changed_cb (CdDevice *device, CcColorPanel *prefs) +{ + const gchar *id; + gboolean ret; + gchar *id_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + CcColorPanelPrivate *priv = prefs->priv; + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + id = cd_device_get_object_path (device); + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (g_strcmp0 (id_tmp, id) == 0) + { + /* populate device */ + gcm_prefs_device_set_model_by_iter (prefs, device, &iter); + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device) +{ + gboolean ret; + GError *error = NULL; + CdDeviceKind kind; + const gchar *icon_name; + const gchar *id; + gchar *sort = NULL; + gchar *title = NULL; + GtkTreeIter parent; + CcColorPanelPrivate *priv = prefs->priv; + + + /* get device properties */ + ret = cd_device_connect_sync (device, priv->cancellable, &error); + if (!ret) + { + g_warning ("failed to connect to the device: %s", error->message); + g_error_free (error); + goto out; + } + + /* get icon */ + kind = cd_device_get_kind (device); + icon_name = gcm_prefs_device_kind_to_icon_name (kind); + + /* italic for non-connected devices */ + title = gcm_device_get_title (device); + + /* create sort order */ + sort = g_strdup_printf ("%s%s", + gcm_prefs_device_kind_to_sort (kind), + title); + + /* watch for changes to update the status icons */ + g_signal_connect (device, "changed", + G_CALLBACK (gcm_prefs_device_changed_cb), prefs); + + /* add to list */ + id = cd_device_get_object_path (device); + g_debug ("add %s to device list", id); + gtk_tree_store_append (priv->list_store_devices, &parent, NULL); + gtk_tree_store_set (priv->list_store_devices, &parent, + GCM_PREFS_COLUMN_DEVICE, device, + GCM_PREFS_COLUMN_DEVICE_PATH, id, + GCM_PREFS_COLUMN_SORT, sort, + GCM_PREFS_COLUMN_TITLE, title, + GCM_PREFS_COLUMN_ICON, icon_name, + -1); + gcm_prefs_device_set_model_by_iter (prefs, device, &parent); +out: + g_free (sort); + g_free (title); +} + +static void +gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *cd_device) +{ + GtkTreeIter iter; + GtkTreeModel *model; + const gchar *id; + gchar *id_tmp; + gboolean ret; + CdDevice *device_tmp; + CcColorPanelPrivate *priv = prefs->priv; + + /* remove */ + id = cd_device_get_object_path (cd_device); + + /* get first element */ + model = GTK_TREE_MODEL (priv->list_store_devices); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* get the other elements */ + do + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (g_strcmp0 (id_tmp, id) == 0) + { + gtk_tree_model_get (model, &iter, + GCM_PREFS_COLUMN_DEVICE, &device_tmp, + -1); + g_signal_handlers_disconnect_by_func (device_tmp, + G_CALLBACK (gcm_prefs_device_changed_cb), + prefs); + gtk_tree_store_remove (GTK_TREE_STORE (model), &iter); + g_free (id_tmp); + g_object_unref (device_tmp); + break; + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +gcm_prefs_update_device_list_extra_entry (CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + gboolean ret; + gchar *id_tmp; + gchar *title = NULL; + GtkTreeIter iter; + + /* select the first device */ + ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter); + if (!ret) + { + /* add the 'No devices detected' entry */ + title = g_strdup_printf ("%s", _("No devices supporting color management detected")); + gtk_tree_store_append (priv->list_store_devices, &iter, NULL); + gtk_tree_store_set (priv->list_store_devices, &iter, + GCM_PREFS_COLUMN_RADIO_VISIBLE, FALSE, + GCM_PREFS_COLUMN_TITLE, title, + -1); + g_free (title); + return; + } + + /* remove the 'No devices detected' entry */ + do + { + gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_devices), &iter, + GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp, + -1); + if (id_tmp == NULL) + { + gtk_tree_store_remove (priv->list_store_devices, &iter); + break; + } + g_free (id_tmp); + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store_devices), &iter)); +} + +static void +gcm_prefs_device_added_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + /* add the device */ + gcm_prefs_add_device (prefs, device); + + /* ensure we're not showing the 'No devices detected' entry */ + gcm_prefs_update_device_list_extra_entry (prefs); +} + +static void +gcm_prefs_changed_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + g_debug ("changed: %s (doing nothing)", cd_device_get_id (device)); +} + +static void +gcm_prefs_device_removed_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkWidget *widget; + gboolean ret; + CcColorPanelPrivate *priv = prefs->priv; + + /* remove from the UI */ + gcm_prefs_remove_device (prefs, device); + + /* ensure we showing the 'No devices detected' entry if required */ + gcm_prefs_update_device_list_extra_entry (prefs); + + /* select the first device */ + ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter); + if (!ret) + return; + + /* click it */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (priv->list_store_devices)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + gtk_tree_selection_select_iter (selection, &iter); +} + +static gboolean +gcm_prefs_tree_model_count_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + guint *i = (guint *) user_data; + (*i)++; + return FALSE; +} + +static void +gcm_prefs_get_devices_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CcColorPanel *prefs = (CcColorPanel *) user_data; + CdClient *client = CD_CLIENT (object); + CdDevice *device; + GError *error = NULL; + GPtrArray *devices; + GtkTreePath *path; + GtkWidget *widget; + guint i; + guint devices_and_profiles = 0; + CcColorPanelPrivate *priv = prefs->priv; + + /* get devices and add them */ + devices = cd_client_get_devices_finish (client, res, &error); + if (devices == NULL) + { + g_warning ("failed to add connected devices: %s", + error->message); + g_error_free (error); + goto out; + } + for (i = 0; i < devices->len; i++) + { + device = g_ptr_array_index (devices, i); + gcm_prefs_add_device (prefs, device); + } + + /* ensure we show the 'No devices detected' entry if empty */ + gcm_prefs_update_device_list_extra_entry (prefs); + + /* set the cursor on the first device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + path = gtk_tree_path_new_from_string ("0"); + gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); + gtk_tree_path_free (path); + + /* if we have only a few devices and profiles expand the treeview + * devices so they can all be seen */ + gtk_tree_model_foreach (GTK_TREE_MODEL (priv->list_store_devices), + gcm_prefs_tree_model_count_cb, + &devices_and_profiles); + if (devices_and_profiles <= GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED) + gtk_tree_view_expand_all (GTK_TREE_VIEW (widget)); + +out: + if (devices != NULL) + g_ptr_array_unref (devices); +} + +static void +gcm_prefs_button_virtual_add_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CdDeviceKind device_kind; + CdDevice *device; + const gchar *model; + const gchar *manufacturer; + gchar *device_id; + GError *error = NULL; + GHashTable *device_props; + CcColorPanelPrivate *priv = prefs->priv; + + /* get device details */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + device_kind = gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + 2; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_model")); + model = gtk_entry_get_text (GTK_ENTRY (widget)); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "entry_virtual_manufacturer")); + manufacturer = gtk_entry_get_text (GTK_ENTRY (widget)); + + /* create device */ + device_id = g_strdup_printf ("%s-%s-%s", + cd_device_kind_to_string (device_kind), + manufacturer, + model); + device_props = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_insert (device_props, + g_strdup ("Kind"), + g_strdup (cd_device_kind_to_string (device_kind))); + g_hash_table_insert (device_props, + g_strdup ("Mode"), + g_strdup (cd_device_mode_to_string (CD_DEVICE_MODE_VIRTUAL))); + g_hash_table_insert (device_props, + g_strdup ("Colorspace"), + g_strdup (cd_colorspace_to_string (CD_COLORSPACE_RGB))); + g_hash_table_insert (device_props, + g_strdup ("Model"), + g_strdup (model)); + g_hash_table_insert (device_props, + g_strdup ("Vendor"), + g_strdup (manufacturer)); + device = cd_client_create_device_sync (priv->client, + device_id, + CD_OBJECT_SCOPE_DISK, + device_props, + priv->cancellable, + &error); + if (device == NULL) + { + g_warning ("Failed to add create virtual device: %s", + error->message); + g_error_free (error); + goto out; + } +out: + g_hash_table_unref (device_props); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_hide (widget); + g_free (device_id); +} + +static void +gcm_prefs_button_virtual_cancel_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv = prefs->priv; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + gtk_widget_hide (widget); +} + +static gboolean +gcm_prefs_virtual_delete_event_cb (GtkWidget *widget, + GdkEvent *event, + CcColorPanel *prefs) +{ + gcm_prefs_button_virtual_cancel_cb (widget, prefs); + return TRUE; +} + +static const gchar * +cd_device_kind_to_localised_string (CdDeviceKind device_kind) +{ + if (device_kind == CD_DEVICE_KIND_DISPLAY) + return C_("Device kind", "Display"); + if (device_kind == CD_DEVICE_KIND_SCANNER) + return C_("Device kind", "Scanner"); + if (device_kind == CD_DEVICE_KIND_PRINTER) + return C_("Device kind", "Printer"); + if (device_kind == CD_DEVICE_KIND_CAMERA) + return C_("Device kind", "Camera"); + if (device_kind == CD_DEVICE_KIND_WEBCAM) + return C_("Device kind", "Webcam"); + return NULL; +} + +static void +gcm_prefs_setup_virtual_combobox (GtkWidget *widget) +{ + guint i; + const gchar *text; + + for (i=CD_DEVICE_KIND_SCANNER; ipriv; + + ret = cd_client_connect_finish (priv->client, + res, + &error); + if (!ret) + { + g_warning ("failed to connect to colord: %s", error->message); + g_error_free (error); + return; + } + + /* set calibrate button sensitivity */ + gcm_prefs_sensor_coldplug (prefs); + + + /* get devices */ + cd_client_get_devices (priv->client, + priv->cancellable, + gcm_prefs_get_devices_cb, + prefs); +} + +static void +gcm_prefs_window_realize_cb (GtkWidget *widget, CcColorPanel *prefs) +{ + prefs->priv->main_window = gtk_widget_get_toplevel (widget); +} + +static const char * +cc_color_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/color"; + else + return "help:gnome-help/color"; +} + +static void +cc_color_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_dispose (GObject *object) +{ + CcColorPanelPrivate *priv = CC_COLOR_PANEL (object)->priv; + + if (priv->settings) + { + g_object_unref (priv->settings); + priv->settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->client != NULL) + { + g_object_unref (priv->client); + priv->client = NULL; + } + if (priv->current_device != NULL) + { + g_object_unref (priv->current_device); + priv->current_device = NULL; + } + if (priv->sensor != NULL) + { + g_object_unref (priv->sensor); + priv->sensor = NULL; + } + + G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object); +} + +static void +cc_color_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object); +} + +static void +cc_color_panel_class_init (CcColorPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcColorPanelPrivate)); + + panel_class->get_help_uri = cc_color_panel_get_help_uri; + + object_class->get_property = cc_color_panel_get_property; + object_class->set_property = cc_color_panel_set_property; + object_class->dispose = cc_color_panel_dispose; + object_class->finalize = cc_color_panel_finalize; +} + +static void +cc_color_panel_init (CcColorPanel *prefs) +{ + CcColorPanelPrivate *priv; + GError *error = NULL; + GtkStyleContext *context; + GtkTreeSelection *selection; + GtkWidget *widget; + + priv = prefs->priv = COLOR_PANEL_PRIVATE (prefs); + + priv->builder = gtk_builder_new (); + gtk_builder_add_from_file (priv->builder, + GNOMECC_UI_DIR "/color.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + priv->cancellable = g_cancellable_new (); + + /* setup defaults */ + priv->settings = g_settings_new (GCM_SETTINGS_SCHEMA); + + /* create list stores */ + priv->list_store_devices = gtk_tree_store_new (GCM_PREFS_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + CD_TYPE_DEVICE, + CD_TYPE_PROFILE, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + + /* assign buttons */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_add_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_remove")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_remove_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_profile_view")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_profile_view_cb), prefs); + + /* create device tree view */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "treeview_devices")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (priv->list_store_devices)); + gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (widget), TRUE); + gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (widget), 0); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + g_signal_connect (selection, "changed", + G_CALLBACK (gcm_prefs_devices_treeview_clicked_cb), + prefs); + g_signal_connect (GTK_TREE_VIEW (widget), "row-activated", + G_CALLBACK (gcm_prefs_treeview_row_activated_cb), + prefs); + g_signal_connect (GTK_TREE_VIEW (widget), "popup-menu", + G_CALLBACK (gcm_prefs_treeview_popup_menu_cb), + prefs); + + /* add columns to the tree view */ + gcm_prefs_add_devices_columns (prefs, GTK_TREE_VIEW (widget)); + + /* force to be at least ~6 rows high */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "scrolledwindow_devices")); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), + 200); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_default")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_default_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_remove")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_delete_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_device_add_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbutton_device_calibrate")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_calibrate_cb), prefs); + + /* make devices toolbar sexy */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "scrolledwindow_devices")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "toolbar_devices")); + context = gtk_widget_get_style_context (widget); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + /* set up virtual dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_virtual")); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gcm_prefs_virtual_delete_event_cb), + prefs); + g_signal_connect (widget, "drag-data-received", + G_CALLBACK (gcm_prefs_virtual_drag_data_received_cb), + prefs); + gcm_prefs_setup_drag_and_drop (widget); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_virtual_add")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_virtual_add_cb), + prefs); + + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_virtual_cancel")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_virtual_cancel_cb), + prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_virtual_type")); + gcm_prefs_setup_virtual_combobox (widget); + + /* set up assign dialog */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "dialog_assign")); + g_signal_connect (widget, "delete-event", + G_CALLBACK (gcm_prefs_profile_delete_event_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_assign_cancel")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_assign_cancel_cb), prefs); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "button_assign_ok")); + g_signal_connect (widget, "clicked", + G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs); + + /* setup icc profiles list */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "combobox_profile")); + gcm_prefs_set_combo_simple_text (widget); + gtk_widget_set_sensitive (widget, FALSE); + g_signal_connect (G_OBJECT (widget), "changed", + G_CALLBACK (gcm_prefs_profile_combo_changed_cb), prefs); + + /* use a device client array */ + priv->client = cd_client_new (); + g_signal_connect (priv->client, "device-added", + G_CALLBACK (gcm_prefs_device_added_cb), prefs); + g_signal_connect (priv->client, "device-removed", + G_CALLBACK (gcm_prefs_device_removed_cb), prefs); + g_signal_connect (priv->client, "changed", + G_CALLBACK (gcm_prefs_changed_cb), prefs); + + /* connect to colord */ + cd_client_connect (priv->client, + priv->cancellable, + gcm_prefs_connect_cb, + prefs); + + /* use the color sensor */ + g_signal_connect (priv->client, "sensor-added", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs); + g_signal_connect (priv->client, "sensor-removed", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs); + + /* set calibrate button sensitivity */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); + + widget = WID (priv->builder, "dialog-vbox1"); + gtk_widget_reparent (widget, (GtkWidget *) prefs); + g_signal_connect (widget, "realize", + G_CALLBACK (gcm_prefs_window_realize_cb), + prefs); + + widget = WID (priv->builder, "linkbutton_help"); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + g_object_set (G_OBJECT (widget), + "uri", "help:ubuntu-help/color-whyimportant", + NULL); +} + +void +cc_color_panel_register (GIOModule *module) +{ + cc_color_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_COLOR_PANEL, + "color", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/cc-shell-marshal.list gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/cc-shell-marshal.list --- gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/cc-shell-marshal.list 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/cc-shell-marshal.list 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1 @@ +VOID:STRING,STRING,STRING diff -Nru gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/gnome-control-center.c gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/gnome-control-center.c --- gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/gnome-control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/gnome-control-center.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1441 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + + +#include "gnome-control-center.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ +#define GMENU_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "cc-panel.h" +#include "cc-shell.h" +#include "cc-shell-category-view.h" +#include "cc-shell-model.h" + +G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) + +#define CONTROL_CENTER_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_CONTROL_CENTER, GnomeControlCenterPrivate)) + +#define W(b,x) GTK_WIDGET (gtk_builder_get_object (b, x)) + +/* Use a fixed width for the shell, since resizing horizontally is more awkward + * for the user than resizing vertically + * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ +#define FIXED_WIDTH 740 +#define UNITY_FIXED_WIDTH 850 +#define FIXED_HEIGHT 650 +#define SMALL_SCREEN_FIXED_HEIGHT 400 + +#define MIN_ICON_VIEW_HEIGHT 300 + +typedef enum { + SMALL_SCREEN_UNSET, + SMALL_SCREEN_TRUE, + SMALL_SCREEN_FALSE +} CcSmallScreen; + +struct _GnomeControlCenterPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GtkWidget *main_vbox; + GtkWidget *scrolled_window; + GtkWidget *search_scrolled; + GtkWidget *current_panel_box; + GtkWidget *current_panel; + char *current_panel_id; + GtkWidget *window; + GtkWidget *search_entry; + GtkWidget *lock_button; + GPtrArray *custom_widgets; + + GMenuTree *menu_tree; + GtkListStore *store; + GHashTable *category_views; + + GtkTreeModel *search_filter; + GtkWidget *search_view; + gchar *filter_string; + + guint32 last_time; + + GIOExtensionPoint *extension_point; + + gchar *default_window_title; + gchar *default_window_icon; + + int monitor_num; + CcSmallScreen small_screen; +}; + +/* Notebook helpers */ +static GtkWidget * +notebook_get_selected_page (GtkWidget *notebook) +{ + int curr; + + curr = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + if (curr == -1) + return NULL; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), curr); +} + +static void +notebook_select_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't select GtkNotebook page %p", page); +} + +static void +notebook_remove_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't find GtkNotebook page to remove %p", page); +} + +static void +notebook_add_page (GtkWidget *notebook, + GtkWidget *page) +{ + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); +} + +static const gchar * +get_icon_name_from_g_icon (GIcon *gicon) +{ + const gchar * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return names[i]; + } + + return NULL; +} + +static gboolean +activate_panel (GnomeControlCenter *shell, + const gchar *id, + const gchar **argv, + const gchar *desktop_file, + const gchar *name, + GIcon *gicon) +{ + GnomeControlCenterPrivate *priv = shell->priv; + GType panel_type = G_TYPE_INVALID; + GList *panels, *l; + GtkWidget *box; + const gchar *icon_name; + + /* check if there is an plugin that implements this panel */ + panels = g_io_extension_point_get_extensions (priv->extension_point); + + if (!desktop_file) + return FALSE; + if (!id) + return FALSE; + + for (l = panels; l != NULL; l = l->next) + { + GIOExtension *extension; + const gchar *name; + + extension = l->data; + + name = g_io_extension_get_name (extension); + + if (!g_strcmp0 (name, id)) + { + panel_type = g_io_extension_get_type (extension); + break; + } + } + + if (panel_type == G_TYPE_INVALID) + { + g_warning ("Could not find the loadable module for panel '%s'", id); + return FALSE; + } + + /* create the panel plugin */ + priv->current_panel = g_object_new (panel_type, "shell", shell, "argv", argv, NULL); + cc_shell_set_active_panel (CC_SHELL (shell), CC_PANEL (priv->current_panel)); + gtk_widget_show (priv->current_panel); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), + cc_panel_get_permission (CC_PANEL (priv->current_panel))); + + box = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (box), 6, 6, 6, 6); + + gtk_container_add (GTK_CONTAINER (box), priv->current_panel); + + gtk_widget_set_name (box, id); + notebook_add_page (priv->notebook, box); + + /* switch to the new panel */ + gtk_widget_show (box); + notebook_select_page (priv->notebook, box); + + /* set the title of the window */ + icon_name = get_icon_name_from_g_icon (gicon); + gtk_window_set_role (GTK_WINDOW (priv->window), id); + gtk_window_set_title (GTK_WINDOW (priv->window), name); + gtk_window_set_default_icon_name (icon_name); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), icon_name); + + priv->current_panel_box = box; + + return TRUE; +} + +static void +_shell_remove_all_custom_widgets (GnomeControlCenterPrivate *priv) +{ + GtkBox *box; + GtkWidget *widget; + guint i; + + /* remove from the header */ + box = GTK_BOX (W (priv->builder, "topright")); + for (i = 0; i < priv->custom_widgets->len; i++) + { + widget = g_ptr_array_index (priv->custom_widgets, i); + gtk_container_remove (GTK_CONTAINER (box), widget); + } + g_ptr_array_set_size (priv->custom_widgets, 0); +} + +static void +shell_show_overview_page (GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + + notebook_select_page (priv->notebook, priv->scrolled_window); + + if (priv->current_panel_box) + notebook_remove_page (priv->notebook, priv->current_panel_box); + priv->current_panel = NULL; + priv->current_panel_box = NULL; + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear the search text */ + g_free (priv->filter_string); + priv->filter_string = g_strdup (""); + gtk_entry_set_text (GTK_ENTRY (priv->search_entry), ""); + gtk_widget_grab_focus (priv->search_entry); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), NULL); + + /* reset window title and icon */ + gtk_window_set_role (GTK_WINDOW (priv->window), NULL); + gtk_window_set_title (GTK_WINDOW (priv->window), priv->default_window_title); + gtk_window_set_default_icon_name (priv->default_window_icon); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), + priv->default_window_icon); + + cc_shell_set_active_panel (CC_SHELL (center), NULL); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); +} + +void +gnome_control_center_set_overview_page (GnomeControlCenter *center) +{ + shell_show_overview_page (center); +} + +static void +item_activated_cb (CcShellCategoryView *view, + gchar *name, + gchar *id, + gchar *desktop_file, + GnomeControlCenter *shell) +{ + GError *err = NULL; + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, &err)) + { + /* TODO: show message to user */ + if (err) + { + g_warning ("Could not active panel \"%s\": %s", id, err->message); + g_error_free (err); + } + } +} + +static gboolean +category_focus_out (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + gtk_icon_view_unselect_all (GTK_ICON_VIEW (view)); + + return FALSE; +} + +static gboolean +category_focus_in (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + GtkTreePath *path; + + if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL)) + { + path = gtk_tree_path_new_from_indices (0, -1); + gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE); + } + + gtk_icon_view_select_path (GTK_ICON_VIEW (view), path); + gtk_tree_path_free (path); + + return FALSE; +} + +static GList * +get_item_views (GnomeControlCenter *shell) +{ + GList *list, *l; + GList *res; + + list = gtk_container_get_children (GTK_CONTAINER (shell->priv->main_vbox)); + res = NULL; + for (l = list; l; l = l->next) + { + if (!CC_IS_SHELL_CATEGORY_VIEW (l->data)) + continue; + res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data))); + } + + g_list_free (list); + + return res; +} + +static gboolean +keynav_failed (GtkIconView *current_view, + GtkDirectionType direction, + GnomeControlCenter *shell) +{ + GList *views, *v; + GtkIconView *new_view; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + gint col, c, dist, d; + GtkTreePath *sel; + gboolean res; + + res = FALSE; + + views = get_item_views (shell); + + for (v = views; v; v = v->next) + { + if (v->data == current_view) + break; + } + + if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL) + { + new_view = v->next->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d < dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL) + { + new_view = v->prev->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d <= dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + g_list_free (views); + + return res; +} + +static gboolean +model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GnomeControlCenterPrivate *priv) +{ + gchar *name, *description; + gchar *needle, *haystack; + gboolean result; + gchar **keywords; + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + COL_DESCRIPTION, &description, + COL_KEYWORDS, &keywords, + -1); + + if (!priv->filter_string || !name) + { + g_free (name); + g_free (description); + g_strfreev (keywords); + return FALSE; + } + + needle = g_utf8_casefold (priv->filter_string, -1); + haystack = g_utf8_casefold (name, -1); + + result = (strstr (haystack, needle) != NULL); + + if (!result && description) + { + gchar *folded; + + folded = g_utf8_casefold (description, -1); + result = (strstr (folded, needle) != NULL); + g_free (folded); + } + + if (!result && keywords) + { + gint i; + gchar *keyword; + + for (i = 0; !result && keywords[i]; i++) + { + keyword = g_utf8_casefold (keywords[i], -1); + result = strstr (keyword, needle) == keyword; + g_free (keyword); + } + } + + g_free (name); + g_free (haystack); + g_free (needle); + g_strfreev (keywords); + + return result; +} + +static gboolean +category_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gchar *filter) +{ + gchar *category; + gboolean result; + + gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1); + + result = (g_strcmp0 (category, filter) == 0); + + g_free (category); + + return result; +} + +static void +search_entry_changed_cb (GtkEntry *entry, + GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + char *str; + + /* if the entry text was set manually (not by the user) */ + if (!g_strcmp0 (priv->filter_string, gtk_entry_get_text (entry))) + return; + + /* Don't re-filter for added trailing or leading spaces */ + str = g_strdup (gtk_entry_get_text (entry)); + g_strstrip (str); + if (!g_strcmp0 (str, priv->filter_string)) + { + g_free (str); + return; + } + + g_free (priv->filter_string); + priv->filter_string = str; + + if (!g_strcmp0 (priv->filter_string, "")) + { + shell_show_overview_page (center); + } + else + { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->search_filter)); + notebook_select_page (priv->notebook, priv->search_scrolled); + } +} + +static gboolean +search_entry_key_press_event_cb (GtkEntry *entry, + GdkEventKey *event, + GnomeControlCenterPrivate *priv) +{ + if (event->keyval == GDK_KEY_Return) + { + GtkTreePath *path; + + path = gtk_tree_path_new_first (); + + priv->last_time = event->time; + + gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->search_view), path); + + gtk_tree_path_free (path); + return TRUE; + } + + if (event->keyval == GDK_KEY_Escape) + { + gtk_entry_set_text (entry, ""); + return TRUE; + } + + return FALSE; +} + +static void +on_search_selection_changed (GtkTreeSelection *selection, + GnomeControlCenter *shell) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + COL_ID, &id, + -1); + + if (id) + cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); + + gtk_tree_selection_unselect_all (selection); + + g_free (id); +} + +static void +setup_search (GnomeControlCenter *shell) +{ + GtkWidget *search_view, *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GnomeControlCenterPrivate *priv = shell->priv; + + g_return_if_fail (priv->store != NULL); + + /* create the search filter */ + priv->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), + NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->search_filter), + (GtkTreeModelFilterVisibleFunc) + model_filter_func, + priv, NULL); + + /* set up the search view */ + priv->search_view = search_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), + GTK_TREE_MODEL (priv->search_filter)); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + "xpad", 15, + "ypad", 10, + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, + "gicon", COL_GICON, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 0, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", COL_NAME, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 15, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Description", renderer, + "text", COL_DESCRIPTION, + NULL); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + priv->search_scrolled = W (priv->builder, "search-scrolled-window"); + gtk_container_add (GTK_CONTAINER (priv->search_scrolled), search_view); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->search_view)), + "changed", + G_CALLBACK (on_search_selection_changed), + shell); + + /* setup the search entry widget */ + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "search-entry"); + priv->search_entry = widget; + priv->filter_string = g_strdup (""); + + g_signal_connect (widget, "changed", G_CALLBACK (search_entry_changed_cb), + shell); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (search_entry_key_press_event_cb), priv); + + gtk_widget_show (priv->search_view); +} + +static void +setup_lock (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + priv->lock_button = W (priv->builder, "lock-button"); +} + +static void +maybe_add_category_view (GnomeControlCenter *shell, + const char *name) +{ + GtkTreeModel *filter; + GtkWidget *categoryview; + + if (g_hash_table_lookup (shell->priv->category_views, name) != NULL) + return; + + if (g_hash_table_size (shell->priv->category_views) > 0) + { + GtkWidget *separator; + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_set_margin_top (separator, 11); + gtk_widget_set_margin_bottom (separator, 10); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), separator, FALSE, FALSE, 0); + gtk_widget_show (separator); + } + + /* create new category view for this category */ + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->priv->store), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + (GtkTreeModelFilterVisibleFunc) category_filter_func, + g_strdup (name), g_free); + + categoryview = cc_shell_category_view_new (name, filter); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), categoryview, FALSE, TRUE, 0); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "desktop-item-activated", + G_CALLBACK (item_activated_cb), shell); + + gtk_widget_show (categoryview); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-in-event", + G_CALLBACK (category_focus_in), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-out-event", + G_CALLBACK (category_focus_out), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "keynav-failed", + G_CALLBACK (keynav_failed), shell); + + g_hash_table_insert (shell->priv->category_views, g_strdup (name), categoryview); +} + +static void +reload_menu (GnomeControlCenter *shell) +{ + GError *error; + GMenuTreeDirectory *d; + GMenuTreeIter *iter; + GMenuTreeItemType next_type; + + error = NULL; + if (!gmenu_tree_load_sync (shell->priv->menu_tree, &error)) + { + g_warning ("Could not load control center menu: %s", error->message); + g_clear_error (&error); + return; + } + + + d = gmenu_tree_get_root_directory (shell->priv->menu_tree); + iter = gmenu_tree_directory_iter (d); + + while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) + { + if (next_type == GMENU_TREE_ITEM_DIRECTORY) + { + GMenuTreeDirectory *subdir; + const gchar *dir_name; + GMenuTreeIter *sub_iter; + GMenuTreeItemType sub_next_type; + + subdir = gmenu_tree_iter_get_directory (iter); + dir_name = gmenu_tree_directory_get_name (subdir); + + maybe_add_category_view (shell, dir_name); + + /* add the items from this category to the model */ + sub_iter = gmenu_tree_directory_iter (subdir); + while ((sub_next_type = gmenu_tree_iter_next (sub_iter)) != GMENU_TREE_ITEM_INVALID) + { + if (sub_next_type == GMENU_TREE_ITEM_ENTRY) + { + GMenuTreeEntry *item = gmenu_tree_iter_get_entry (sub_iter); + cc_shell_model_add_item (CC_SHELL_MODEL (shell->priv->store), + dir_name, + item); + gmenu_tree_item_unref (item); + } + } + + gmenu_tree_iter_unref (sub_iter); + gmenu_tree_item_unref (subdir); + } + } + + gmenu_tree_iter_unref (iter); +} + +static void +on_menu_changed (GMenuTree *monitor, + GnomeControlCenter *shell) +{ + gtk_list_store_clear (shell->priv->store); + reload_menu (shell); +} + +static void +setup_model (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + gtk_widget_set_margin_top (shell->priv->main_vbox, 8); + gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8); + gtk_widget_set_margin_left (shell->priv->main_vbox, 12); + gtk_widget_set_margin_right (shell->priv->main_vbox, 12); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window))); + + priv->store = (GtkListStore *) cc_shell_model_new (); + priv->category_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->menu_tree = gmenu_tree_new_for_path (MENUDIR "/gnomecc.menu", 0); + + reload_menu (shell); + + g_signal_connect (priv->menu_tree, "changed", G_CALLBACK (on_menu_changed), shell); +} + +static void +load_panel_plugins (GnomeControlCenter *shell) +{ + GList *modules; + + /* only allow this function to be run once to prevent modules being loaded + * twice + */ + if (shell->priv->extension_point) + return; + + /* make sure the base type is registered */ + g_type_from_name ("CcPanel"); + + shell->priv->extension_point + = g_io_extension_point_register (CC_SHELL_PANEL_EXTENSION_POINT); + + /* load all the plugins in the panels directory */ + modules = g_io_modules_load_all_in_directory (PANELS_DIR); + g_list_free (modules); + +} + + +static void +home_button_clicked_cb (GtkButton *button, + GnomeControlCenter *shell) +{ + shell_show_overview_page (shell); +} + +static void +notebook_page_notify_cb (GtkNotebook *notebook, + GParamSpec *spec, + GnomeControlCenterPrivate *priv) +{ + int nat_height; + GtkWidget *child; + + child = notebook_get_selected_page (GTK_WIDGET (notebook)); + + /* make sure the home button is shown on all pages except the overview page */ + + if (child == priv->scrolled_window || child == priv->search_scrolled) + { + gtk_widget_hide (W (priv->builder, "home-button")); + gtk_widget_show (W (priv->builder, "search-entry")); + gtk_widget_hide (W (priv->builder, "lock-button")); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + UNITY_FIXED_WIDTH, NULL, &nat_height); + else + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); + } + else + { + gtk_widget_show (W (priv->builder, "home-button")); + gtk_widget_hide (W (priv->builder, "search-entry")); + /* set the scrolled window small so that it doesn't force + the window to be larger than this panel */ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + UNITY_FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + UNITY_FIXED_WIDTH, + nat_height); + } + else { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } + } +} + +/* CcShell implementation */ +static void +_shell_embed_widget_in_header (CcShell *shell, + GtkWidget *widget) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkBox *box; + + /* add to header */ + box = GTK_BOX (W (priv->builder, "topright")); + gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + g_ptr_array_add (priv->custom_widgets, g_object_ref (widget)); +} + +/* CcShell implementation */ +static gboolean +_shell_set_active_panel_from_id (CcShell *shell, + const gchar *start_id, + const gchar **argv, + GError **err) +{ + GtkTreeIter iter; + gboolean iter_valid; + gchar *name = NULL; + gchar *desktop = NULL; + GIcon *gicon = NULL; + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkWidget *old_panel; + + /* When loading the same panel again, just set the argv */ + if (g_strcmp0 (priv->current_panel_id, start_id) == 0) + { + g_object_set (G_OBJECT (priv->current_panel), "argv", argv, NULL); + return TRUE; + } + + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + + /* find the details for this item */ + while (iter_valid) + { + gchar *id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + COL_NAME, &name, + COL_DESKTOP_FILE, &desktop, + COL_GICON, &gicon, + COL_ID, &id, + -1); + + if (id && !strcmp (id, start_id)) + { + g_free (id); + break; + } + else + { + g_free (id); + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + name = NULL; + id = NULL; + desktop = NULL; + gicon = NULL; + } + + iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + if (!name) + { + g_warning ("Could not find settings panel \"%s\"", start_id); + } + else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop, + name, gicon) == FALSE) + { + /* Failed to activate the panel for some reason */ + old_panel = priv->current_panel_box; + priv->current_panel_box = NULL; + notebook_select_page (priv->notebook, priv->scrolled_window); + if (old_panel) + notebook_remove_page (priv->notebook, old_panel); + } + else + { + priv->current_panel_id = g_strdup (start_id); + } + + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + return TRUE; +} + +static GtkWidget * +_shell_get_toplevel (CcShell *shell) +{ + return GNOME_CONTROL_CENTER (shell)->priv->window; +} + +/* GObject Implementation */ +static void +gnome_control_center_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_dispose (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + g_free (priv->current_panel_id); + + if (priv->custom_widgets) + { + g_ptr_array_unref (priv->custom_widgets); + priv->custom_widgets = NULL; + } + if (priv->window) + { + gtk_widget_destroy (priv->window); + priv->window = NULL; + + /* destroying the window will destroy its children */ + priv->notebook = NULL; + priv->search_entry = NULL; + priv->search_view = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->store) + { + g_object_unref (priv->store); + priv->store = NULL; + } + + if (priv->search_filter) + { + g_object_unref (priv->search_filter); + priv->search_filter = NULL; + } + + + G_OBJECT_CLASS (gnome_control_center_parent_class)->dispose (object); +} + +static void +gnome_control_center_finalize (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + if (priv->filter_string) + { + g_free (priv->filter_string); + priv->filter_string = NULL; + } + + if (priv->default_window_title) + { + g_free (priv->default_window_title); + priv->default_window_title = NULL; + } + + if (priv->default_window_icon) + { + g_free (priv->default_window_icon); + priv->default_window_icon = NULL; + } + + if (priv->menu_tree) + { + g_signal_handlers_disconnect_by_func (priv->menu_tree, + G_CALLBACK (on_menu_changed), object); + g_object_unref (priv->menu_tree); + } + + if (priv->category_views) + { + g_hash_table_destroy (priv->category_views); + } + + G_OBJECT_CLASS (gnome_control_center_parent_class)->finalize (object); +} + +static void +gnome_control_center_class_init (GnomeControlCenterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcShellClass *shell_class = CC_SHELL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GnomeControlCenterPrivate)); + + object_class->get_property = gnome_control_center_get_property; + object_class->set_property = gnome_control_center_set_property; + object_class->dispose = gnome_control_center_dispose; + object_class->finalize = gnome_control_center_finalize; + + shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id; + shell_class->embed_widget_in_header = _shell_embed_widget_in_header; + shell_class->get_toplevel = _shell_get_toplevel; +} + +static gboolean +window_key_press_event (GtkWidget *win, + GdkEventKey *event, + GnomeControlCenter *self) +{ + GdkKeymap *keymap; + gboolean retval; + GdkModifierType state; + + if (event->state == 0) + return FALSE; + + retval = FALSE; + state = event->state; + keymap = gdk_keymap_get_default (); + gdk_keymap_add_virtual_modifiers (keymap, &state); + state = state & gtk_accelerator_get_default_mod_mask (); + + if (state == GDK_CONTROL_MASK) + { + switch (event->keyval) + { + case GDK_KEY_s: + case GDK_KEY_S: + case GDK_KEY_f: + case GDK_KEY_F: + if (gtk_widget_get_visible (self->priv->search_entry)) + { + gtk_widget_grab_focus (self->priv->search_entry); + retval = TRUE; + } + break; + case GDK_KEY_Q: + case GDK_KEY_q: + g_object_unref (self); + retval = TRUE; + break; + case GDK_KEY_W: + case GDK_KEY_w: + if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) + shell_show_overview_page (self); + retval = TRUE; + break; + } + } + return retval; +} + +static gint +get_monitor_height (GnomeControlCenter *self) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* We cannot use workarea here, as this wouldn't + * be updated when we read it after a monitors-changed signal */ + screen = gtk_widget_get_screen (self->priv->window); + gdk_screen_get_monitor_geometry (screen, self->priv->monitor_num, &rect); + + return rect.height; +} + +static gboolean +update_monitor_number (GnomeControlCenter *self) +{ + gboolean changed = FALSE; + GtkWidget *widget; + GdkScreen *screen; + GdkWindow *window; + int monitor; + + widget = self->priv->window; + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (widget); + monitor = gdk_screen_get_monitor_at_window (screen, window); + if (self->priv->monitor_num != monitor) + { + self->priv->monitor_num = monitor; + changed = TRUE; + } + + return changed; +} + +static CcSmallScreen +is_small (GnomeControlCenter *self) +{ + if (get_monitor_height (self) <= FIXED_HEIGHT) + return SMALL_SCREEN_TRUE; + return SMALL_SCREEN_FALSE; +} + +static void +update_small_screen_settings (GnomeControlCenter *self) +{ + CcSmallScreen small; + + update_monitor_number (self); + small = is_small (self); + + if (small == SMALL_SCREEN_TRUE) + { + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), TRUE); + + if (self->priv->small_screen != small) + gtk_window_maximize (GTK_WINDOW (self->priv->window)); + } + else + { + if (self->priv->small_screen != small) + gtk_window_unmaximize (GTK_WINDOW (self->priv->window)); + + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), FALSE); + } + + self->priv->small_screen = small; + + /* And update the minimum sizes */ + notebook_page_notify_cb (GTK_NOTEBOOK (self->priv->notebook), NULL, self->priv); +} + +static gboolean +main_window_configure_cb (GtkWidget *widget, + GdkEvent *event, + GnomeControlCenter *self) +{ + update_small_screen_settings (self); + return FALSE; +} + +static void +application_set_cb (GObject *object, + GParamSpec *pspec, + GnomeControlCenter *self) +{ + /* update small screen settings now - to avoid visible resizing, we want + * to do it before showing the window, and GtkApplicationWindow cannot be + * realized unless its application property has been set */ + if (gtk_window_get_application (GTK_WINDOW (self->priv->window))) + { + gtk_widget_realize (self->priv->window); + update_small_screen_settings (self); + } +} + +static void +monitors_changed_cb (GdkScreen *screen, + GnomeControlCenter *self) +{ + /* We reset small_screen_set to make sure that the + * window gets maximised if need be, in update_small_screen_settings() */ + self->priv->small_screen = SMALL_SCREEN_UNSET; + update_small_screen_settings (self); +} + +static void +gnome_control_center_init (GnomeControlCenter *self) +{ + GError *err = NULL; + GnomeControlCenterPrivate *priv; + GdkScreen *screen; + + priv = self->priv = CONTROL_CENTER_PRIVATE (self); + +#ifdef HAVE_CHEESE + if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + { + g_critical ("Clutter-GTK init failed"); + return; + } +#endif /* HAVE_CHEESE */ + + priv->monitor_num = -1; + self->priv->small_screen = SMALL_SCREEN_UNSET; + + /* load the user interface */ + priv->builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (priv->builder, UIDIR "/shell.ui", &err)) + { + g_critical ("Could not build interface: %s", err->message); + g_error_free (err); + + return; + } + + /* connect various signals */ + priv->window = W (priv->builder, "main-window"); + gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (priv->window), TRUE); + screen = gtk_widget_get_screen (priv->window); + g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self); + g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self); + g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self); + g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self); + g_signal_connect_after (priv->window, "key_press_event", + G_CALLBACK (window_key_press_event), self); + + priv->notebook = W (priv->builder, "notebook"); + + /* Main scrolled window */ + priv->scrolled_window = W (priv->builder, "scrolledwindow1"); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); + else + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + priv->main_vbox = W (priv->builder, "main-vbox"); + g_signal_connect (priv->notebook, "notify::page", + G_CALLBACK (notebook_page_notify_cb), priv); + + g_signal_connect (gtk_builder_get_object (priv->builder, "home-button"), + "clicked", G_CALLBACK (home_button_clicked_cb), self); + + /* keep a list of custom widgets to unload on panel change */ + priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* load the available settings panels */ + setup_model (self); + + /* load the panels that are implemented as plugins */ + load_panel_plugins (self); + + /* setup search functionality */ + setup_search (self); + + setup_lock (self); + + /* store default window title and name */ + priv->default_window_title = g_strdup (gtk_window_get_title (GTK_WINDOW (priv->window))); + priv->default_window_icon = g_strdup (gtk_window_get_icon_name (GTK_WINDOW (priv->window))); + + notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv); +} + +GnomeControlCenter * +gnome_control_center_new (void) +{ + return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL); +} + +void +gnome_control_center_present (GnomeControlCenter *center) +{ + gtk_window_present (GTK_WINDOW (center->priv->window)); +} + +void +gnome_control_center_show (GnomeControlCenter *center, + GtkApplication *app) +{ + gtk_window_set_application (GTK_WINDOW (center->priv->window), app); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window))); +} diff -Nru gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/Makefile.am gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/Makefile.am --- gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/Makefile.am 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,77 @@ +INCLUDES = \ + -I$(top_srcdir) \ + $(SHELL_CFLAGS) \ + $(CHEESE_CFLAGS) + +bin_PROGRAMS = gnome-control-center + +MARSHAL_FILES = cc-shell-marshal.c cc-shell-marshal.h +BUILT_SOURCES = $(MARSHAL_FILES) + +cc-shell-marshal.h: cc-shell-marshal.list + $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=cc_shell_marshal $< --header > $@ + +cc-shell-marshal.c: cc-shell-marshal.list + $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=cc_shell_marshal $< --body --header > $@ + +gnome_control_center_SOURCES = \ + control-center.c \ + cc-shell-log.c \ + cc-shell-log.h \ + gnome-control-center.c \ + gnome-control-center.h \ + cc-shell-category-view.c \ + cc-shell-category-view.h \ + cc-shell-item-view.c \ + cc-shell-item-view.h \ + cc-shell-model.c \ + cc-shell-model.h \ + cc-editable-entry.c \ + cc-editable-entry.h \ + cc-panel.c \ + cc-panel.h \ + cc-shell.c \ + cc-shell.h \ + $(MARSHAL_FILES) + +gnome_control_center_LDADD = \ + $(SHELL_LIBS) \ + $(CHEESE_LIBS) + +gnome_control_center_LDFLAGS = -export-dynamic + +AM_CPPFLAGS = \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + -DUIDIR="\"$(uidir)\"" \ + -DMENUDIR="\"$(menudir)\"" \ + -DPANELS_DIR="\"$(PANELS_DIR)\"" + +menudir = $(sysconfdir)/xdg/menus +menu_DATA = gnomecc.menu + +gnomecc.menu: gnomecc.menu.in + $(AM_V_GEN) cat $< | sed 's,@applicationsdir@,$(datadir)/applications/,' > $@ + +uidir = $(pkgdatadir)/ui +ui_DATA = shell.ui + +sysdir = $(datadir)/applications +sys_in_files = gnome-control-center.desktop.in +sys_DATA = $(sys_in_files:.desktop.in=.desktop) +@INTLTOOL_DESKTOP_RULE@ + +directorydir = $(datadir)/desktop-directories +directory_in_files = gnomecc.directory.in +directory_DATA = $(directory_in_files:.directory.in=.directory) +@INTLTOOL_DIRECTORY_RULE@ + +EXTRA_DIST = \ + $(ui_DATA) \ + gnome-control-center.desktop.in.in \ + gnomecc.directory.in \ + gnomecc.menu.in \ + cc-shell-marshal.list + +DISTCLEANFILES = gnome-control-center.desktop gnome-control-center.desktop.in gnomecc.directory gnomecc.menu + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/shell.ui gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/shell.ui --- gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/shell.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/60_ubuntu_nav_bar.patch/shell/shell.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,189 @@ + + + + + + System Settings + False + preferences-desktop + center + + + True + vertical + + + True + + + + True + + + + True + 5 + 5 + 10 + 5 + + + True + + + True + False + 0 + 1 + none + False + + + False + True + True + True + False + image1 + True + + + All Settings + + + + + + + False + 0 + + + + + True + 1 + 0 + + + True + horizontal + + + 210 + True + True + + edit-find-symbolic + False + False + + + + + False + True + + + + + + + 1 + + + + + + + + + True + True + + + + + False + 0 + + + + + True + True + False + + + True + True + never + automatic + in + + + True + queue + none + + + True + vertical + + + + + + + + + + + + True + True + automatic + automatic + in + + + + + + + + 1 + + + + + + + + + + + + + + + + + vertical + + + + + + + True + False + view-grid-symbolic + True + 16 + + diff -Nru gnome-control-center-3.6.3/.pc/61_workaround_online_account.patch/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in gnome-control-center-3.6.3/.pc/61_workaround_online_account.patch/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/61_workaround_online_account.patch/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/61_workaround_online_account.patch/panels/online-accounts/gnome-online-accounts-panel.desktop.in.in 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Online Accounts +_Comment=Manage online accounts +Exec=gnome-control-center online-accounts +Icon=goa-panel +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=Online Accounts +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=online-accounts +# Translators: those are keywords for the online-accounts control-center panel +_Keywords=Google;Facebook;Twitter;Yahoo;Web;Online;Chat;Calendar;Mail;Contact; diff -Nru gnome-control-center-3.6.3/.pc/64_restore_terminal_keyboard_shortcut.patch/panels/keyboard/01-launchers.xml.in gnome-control-center-3.6.3/.pc/64_restore_terminal_keyboard_shortcut.patch/panels/keyboard/01-launchers.xml.in --- gnome-control-center-3.6.3/.pc/64_restore_terminal_keyboard_shortcut.patch/panels/keyboard/01-launchers.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/64_restore_terminal_keyboard_shortcut.patch/panels/keyboard/01-launchers.xml.in 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/90_force_fallback.patch/panels/info/info.ui gnome-control-center-3.6.3/.pc/90_force_fallback.patch/panels/info/info.ui --- gnome-control-center-3.6.3/.pc/90_force_fallback.patch/panels/info/info.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/90_force_fallback.patch/panels/info/info.ui 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,1341 @@ + + + + + False + 10 + False + True + True + dialog + + + True + False + vertical + 2 + + + True + False + end + + + + + + gtk-close + True + True + True + True + True + False + True + + + False + False + 1 + + + + + False + True + end + 0 + + + + + True + False + 5 + vertical + + + True + False + 10 + vertical + + + True + False + 0 + Select how other media should be handled + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + vertical + + + True + False + 6 + 10 + + + True + False + + + 1 + 0 + + + + + True + False + 0 + _Action: + True + + + 0 + 1 + + + + + True + False + + + 1 + 1 + + + + + True + False + 0 + _Type: + True + media_other_type_combobox + + + 0 + 0 + + + + + False + True + 1 + + + + + + + False + True + 1 + + + + + False + True + 0 + + + + + False + True + 1 + + + + + + button1 + + + + False + + + True + False + 10 + vertical + + + True + False + 10 + horizontal + + + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + True + False + 20 + vertical + + + True + False + False + False + + + True + False + 20 + + + True + False + 18 + vertical + + + True + False + UbuntuLogo.png + + + False + False + 0 + + + + + True + False + Version 3.0 + True + + + + + + False + False + 1 + + + + + True + False + 6 + 3 + 12 + 5 + + + False + True + 1 + Device name + name_entry + + + + + + True + False + 1 + Memory + memory_label + + + + 1 + 2 + + + + + True + False + 1 + Processor + processor_label + + + + 2 + 3 + + + + + True + False + 1 + OS type + os_type_label + + + + 4 + 5 + + + + + True + False + 1 + Disk + disk_label + + + + 5 + 6 + + + + + False + 0 + + False + + + 1 + 2 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 1 + 2 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 2 + 3 + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 4 + 5 + + + + + True + False + 0 + Calculating... + True + + + 1 + 2 + 5 + 6 + + + + + True + False + + + + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 5 + 6 + GTK_FILL + + + + + True + False + 1 + Graphics + + + + 3 + 4 + + + + + True + False + + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 3 + 4 + + + + + False + False + 2 + + + + + True + False + end + horizontal + + + + + + Updates Available + True + True + False + True + + + False + True + 1 + + + + + False + False + end + 3 + + + + + + + + + True + False + Overview + + + False + + + + + True + False + center + start + 20 + 10 + vertical + + + True + False + start + start + 6 + 3 + 12 + 12 + + + True + False + 1 + _Web + True + + + + + + True + False + 1 + _Mail + True + + + + 1 + 2 + + + + + True + False + 1 + _Calendar + True + + + + 2 + 3 + + + + + True + False + 1 + M_usic + True + + + + 3 + 4 + + + + + True + False + 1 + _Video + True + + + + 4 + 5 + + + + + True + False + + + + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 2 + 3 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + True + False + + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + True + False + 1 + _Photos + True + + + + 5 + 6 + + + + + True + False + + + + 2 + 3 + 5 + 6 + GTK_FILL + + + + + + + + + + + + + + + + + + + + + + + False + False + 0 + + + + + 1 + + + + + True + False + Default Applications + + + 1 + False + + + + + True + False + horizontal + + + True + False + + + True + False + 10 + 10 + vertical + + + True + False + 10 + start + False + vertical + + + True + False + 10 + vertical + + + True + False + 0 + Select how media should be handled + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + vertical + + + True + False + 5 + 2 + 6 + 6 + + + True + False + 1 + CD _audio + True + media_audio_cdda_combobox + + + + GTK_FILL + + + + + + True + False + 1 + _DVD video + True + media_video_dvd_combobox + + + + 1 + 2 + GTK_FILL + + + + + + True + False + x-content/audio-cdda + + + 1 + 2 + GTK_FILL + + + + + True + False + x-content/video-dvd + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Music player + True + media_music_player_combobox + + + + 2 + 3 + GTK_FILL + + + + + + True + False + x-content/audio-player + + + 1 + 2 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Photos + True + media_dcf_combobox + + + + 3 + 4 + GTK_FILL + + + + + + True + False + x-content/image-dcf + + + 1 + 2 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + _Software + True + media_software_combobox + + + + 4 + 5 + GTK_FILL + + + + + + True + False + x-content/unix-software + + + 1 + 2 + 4 + 5 + GTK_FILL + GTK_FILL + + + + + False + True + 0 + + + + + True + False + horizontal + + + _Other Media... + True + True + True + False + True + + + False + False + end + 0 + + + + + True + True + 1 + + + + + + + False + True + 1 + + + + + False + True + 0 + + + + + False + False + 0 + + + + + _Never prompt or start programs on media insertion + True + True + False + False + True + 0 + True + end + False + + + False + False + 1 + + + + + + + True + False + 0 + + + + + 2 + + + + + True + False + Removable Media + + + 2 + False + + + + + True + False + 20 + + + True + False + 4 + 2 + 12 + 10 + + + True + False + 1 + Driver + + + + GTK_FILL + GTK_FILL + + + + + True + False + 1 + Experience + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + Forced _Fallback Mode + True + right + + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + GTK_FILL + + + + + True + False + 0 + Unknown + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + False + start + center + horizontal + + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + False + True + 0 + 0 + The next login will use the fallback mode intended for unsupported graphics hardware. + True + True + + + + + + 1 + 2 + 3 + 4 + + + + + True + False + 1 + right + + + 3 + 4 + GTK_FILL + + + + + + + 3 + + + + + True + False + Graphics + graphics_label + + + 3 + False + + + + + True + True + 0 + + + + + True + True + 1 + + + + + True + True + 0 + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/91_unity_no_printing_panel.patch/panels/printers/gnome-printers-panel.desktop.in.in gnome-control-center-3.6.3/.pc/91_unity_no_printing_panel.patch/panels/printers/gnome-printers-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/91_unity_no_printing_panel.patch/panels/printers/gnome-printers-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/91_unity_no_printing_panel.patch/panels/printers/gnome-printers-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,14 @@ +[Desktop Entry] +_Name=Printers +_Comment=Change printer settings +Exec=gnome-control-center printers +Icon=printer +Terminal=false +Type=Application +StartupNotify=true +# The X-GNOME-Settings-Panel is necessary to show in the main shell UI +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Settings-Panel=printers +# Translators: those are keywords for the printing control-center panel +_Keywords=Printer;Queue;Print;Paper;Ink;Toner; diff -Nru gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/net-proxy.c gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/net-proxy.c --- gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/net-proxy.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/net-proxy.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,388 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2011-2012 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include + +#include "net-proxy.h" + +#define NET_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NET_TYPE_PROXY, NetProxyPrivate)) + +struct _NetProxyPrivate +{ + GSettings *settings; + GtkBuilder *builder; +}; + +G_DEFINE_TYPE (NetProxy, net_proxy, NET_TYPE_OBJECT) + +static void +check_wpad_warning (NetProxy *proxy) +{ + GtkWidget *widget; + gchar *autoconfig_url = NULL; + GString *string = NULL; + gboolean ret = FALSE; + guint mode; + + string = g_string_new (""); + + /* check we're using 'Automatic' */ + mode = g_settings_get_enum (proxy->priv->settings, "mode"); + if (mode != 2) + goto out; + + /* see if the PAC is blank */ + autoconfig_url = g_settings_get_string (proxy->priv->settings, + "autoconfig-url"); + ret = autoconfig_url == NULL || + autoconfig_url[0] == '\0'; + if (!ret) + goto out; + + g_string_append (string, ""); + + /* TRANSLATORS: this is when the use leaves the PAC textbox blank */ + g_string_append (string, _("Web Proxy Autodiscovery is used when a Configuration URL is not provided.")); + + g_string_append (string, "\n"); + + /* TRANSLATORS: WPAD is bad: if you enable it on an untrusted + * network, then anyone else on that network can tell your + * machine that it should proxy all of your web traffic + * through them. */ + g_string_append (string, _("This is not recommended for untrusted public networks.")); + g_string_append (string, ""); +out: + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "label_proxy_warning")); + gtk_label_set_markup (GTK_LABEL (widget), string->str); + g_free (autoconfig_url); + g_string_free (string, TRUE); +} + +static void +settings_changed_cb (GSettings *settings, + const gchar *key, + NetProxy *proxy) +{ + check_wpad_warning (proxy); +} + +static void +panel_proxy_mode_combo_setup_widgets (NetProxy *proxy, guint value) +{ + GtkWidget *widget; + + /* hide or show the PAC text box */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_url")); + gtk_widget_set_visible (widget, value == 2); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_url")); + gtk_widget_set_visible (widget, value == 2); + + /* hide or show the manual entry text boxes */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_http")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_http")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "spinbutton_proxy_http")); + gtk_widget_set_visible (widget, value == 1); + + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_https")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_https")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "spinbutton_proxy_https")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_ftp")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_ftp")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "spinbutton_proxy_ftp")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_socks")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_socks")); + gtk_widget_set_visible (widget, value == 1); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "spinbutton_proxy_socks")); + gtk_widget_set_visible (widget, value == 1); + + /* perhaps show the wpad warning */ + check_wpad_warning (proxy); +} + +static void +panel_set_value_for_combo (NetProxy *proxy, GtkComboBox *combo_box, gint value) +{ + gboolean ret; + gint value_tmp; + GtkTreeIter iter; + GtkTreeModel *model; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* try to make the UI match the setting */ + do { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) { + gtk_combo_box_set_active_iter (combo_box, &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); + + /* hide or show the correct widgets */ + panel_proxy_mode_combo_setup_widgets (proxy, value); +} + +static void +panel_proxy_mode_combo_changed_cb (GtkWidget *widget, NetProxy *proxy) +{ + gboolean ret; + gint value; + GtkTreeIter iter; + GtkTreeModel *model; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set */ + g_settings_set_enum (proxy->priv->settings, "mode", value); + + /* hide or show the correct widgets */ + panel_proxy_mode_combo_setup_widgets (proxy, value); +} + +static GtkWidget * +net_proxy_add_to_notebook (NetObject *object, + GtkNotebook *notebook, + GtkSizeGroup *heading_size_group) +{ + GtkWidget *widget; + GtkWindow *window; + NetProxy *proxy = NET_PROXY (object); + + /* add widgets to size group */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "heading_proxy_method")); + gtk_size_group_add_widget (heading_size_group, widget); + + /* reparent */ + window = GTK_WINDOW (gtk_builder_get_object (proxy->priv->builder, + "window_tmp")); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "grid5")); + g_object_ref (widget); + gtk_container_remove (GTK_CONTAINER (window), widget); + gtk_notebook_append_page (notebook, widget, NULL); + g_object_unref (widget); + return widget; +} + +static void +net_proxy_finalize (GObject *object) +{ + NetProxy *proxy = NET_PROXY (object); + NetProxyPrivate *priv = proxy->priv; + + g_clear_object (&priv->settings); + g_clear_object (&priv->builder); + + G_OBJECT_CLASS (net_proxy_parent_class)->finalize (object); +} + +static void +net_proxy_class_init (NetProxyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NetObjectClass *parent_class = NET_OBJECT_CLASS (klass); + + object_class->finalize = net_proxy_finalize; + parent_class->add_to_notebook = net_proxy_add_to_notebook; + g_type_class_add_private (klass, sizeof (NetProxyPrivate)); +} + +static void +net_proxy_init (NetProxy *proxy) +{ + GError *error = NULL; + gint value; + GSettings *settings_tmp; + GtkAdjustment *adjustment; + GtkWidget *widget; + + proxy->priv = NET_PROXY_GET_PRIVATE (proxy); + + proxy->priv->builder = gtk_builder_new (); + gtk_builder_add_from_file (proxy->priv->builder, + GNOMECC_UI_DIR "/network-proxy.ui", + &error); + if (error != NULL) { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + proxy->priv->settings = g_settings_new ("org.gnome.system.proxy"); + g_signal_connect (proxy->priv->settings, + "changed", + G_CALLBACK (settings_changed_cb), + proxy); + + /* explicitly set this to false as the panel has no way of + * linking the http and https proxies them together */ + g_settings_set_boolean (proxy->priv->settings, + "use-same-proxy", + FALSE); + + /* actions */ + value = g_settings_get_enum (proxy->priv->settings, "mode"); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "combobox_proxy_mode")); + panel_set_value_for_combo (proxy, GTK_COMBO_BOX (widget), value); + g_signal_connect (widget, "changed", + G_CALLBACK (panel_proxy_mode_combo_changed_cb), + proxy); + + /* bind the proxy values */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_url")); + g_settings_bind (proxy->priv->settings, "autoconfig-url", + widget, "text", + G_SETTINGS_BIND_DEFAULT); + + /* bind the HTTP proxy values */ + settings_tmp = g_settings_get_child (proxy->priv->settings, "http"); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_http")); + g_settings_bind (settings_tmp, "host", + widget, "text", + G_SETTINGS_BIND_DEFAULT); + adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (proxy->priv->builder, + "adjustment_proxy_port_http")); + g_settings_bind (settings_tmp, "port", + adjustment, "value", + G_SETTINGS_BIND_DEFAULT); + g_object_unref (settings_tmp); + + /* bind the HTTPS proxy values */ + settings_tmp = g_settings_get_child (proxy->priv->settings, "https"); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_https")); + g_settings_bind (settings_tmp, "host", + widget, "text", + G_SETTINGS_BIND_DEFAULT); + adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (proxy->priv->builder, + "adjustment_proxy_port_https")); + g_settings_bind (settings_tmp, "port", + adjustment, "value", + G_SETTINGS_BIND_DEFAULT); + g_object_unref (settings_tmp); + + /* bind the FTP proxy values */ + settings_tmp = g_settings_get_child (proxy->priv->settings, "ftp"); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_ftp")); + g_settings_bind (settings_tmp, "host", + widget, "text", + G_SETTINGS_BIND_DEFAULT); + adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (proxy->priv->builder, + "adjustment_proxy_port_ftp")); + g_settings_bind (settings_tmp, "port", + adjustment, "value", + G_SETTINGS_BIND_DEFAULT); + g_object_unref (settings_tmp); + + /* bind the SOCKS proxy values */ + settings_tmp = g_settings_get_child (proxy->priv->settings, "socks"); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "entry_proxy_socks")); + g_settings_bind (settings_tmp, "host", + widget, "text", + G_SETTINGS_BIND_DEFAULT); + adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (proxy->priv->builder, + "adjustment_proxy_port_socks")); + g_settings_bind (settings_tmp, "port", + adjustment, "value", + G_SETTINGS_BIND_DEFAULT); + g_object_unref (settings_tmp); + + /* set header to something sane */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "image_proxy_device")); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), + "preferences-system-network", + GTK_ICON_SIZE_DIALOG); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "label_proxy_device")); + gtk_label_set_label (GTK_LABEL (widget), + _("Proxy")); + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "label_proxy_status")); + gtk_label_set_label (GTK_LABEL (widget), ""); + + /* hide the switch until we get some more detail in the mockup */ + widget = GTK_WIDGET (gtk_builder_get_object (proxy->priv->builder, + "device_proxy_off_switch")); + if (widget != NULL) + gtk_widget_hide (widget); +} + +NetProxy * +net_proxy_new (void) +{ + NetProxy *proxy; + proxy = g_object_new (NET_TYPE_PROXY, + "removable", FALSE, + "id", "proxy", + NULL); + return NET_PROXY (proxy); +} diff -Nru gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/network-proxy.ui gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/network-proxy.ui --- gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/network-proxy.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/92_ubuntu_system_proxy.patch/panels/network/network-proxy.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,427 @@ + + + + + 65535 + 1 + + + 65535 + 1 + + + 65535 + 1 + + + 65535 + 1 + + + + + + + + + + + None + 0 + + + Manual + 1 + + + Automatic + 2 + + + + + False + + + True + False + start + 12 + 10 + 6 + + + True + False + end + start + 1 + 48 + preferences-system-network + 6 + + + 0 + 0 + 1 + 1 + + + + + True + False + start + True + 3 + + + True + False + 0 + Proxy + end + + + + + + + False + False + 0 + + + + + True + False + 0 + Not connected + + + False + False + 1 + + + + + 1 + 0 + 1 + 1 + + + + + True + False + end + start + + + False + True + True + end + start + + + + + 2 + 0 + 1 + 1 + + + + + True + False + 1 + _Method + True + combobox_proxy_mode + + + + 0 + 1 + 1 + 1 + + + + + True + False + 0 + 1 + liststore_proxy_method + + + 1 + 1 + 2 + 1 + + + + + True + False + 1 + _Configuration URL + True + entry_proxy_url + + + + 0 + 2 + 1 + 1 + + + + + True + True + + True + + + 1 + 2 + 2 + 1 + + + + + True + False + 1 + _HTTP Proxy + True + entry_proxy_http + + + + 0 + 3 + 1 + 1 + + + + + True + False + 1 + H_TTPS Proxy + True + entry_proxy_https + + + + 0 + 4 + 1 + 1 + + + + + True + False + 1 + _FTP Proxy + True + entry_proxy_ftp + + + + 0 + 5 + 1 + 1 + + + + + True + False + 1 + _Socks Host + True + entry_proxy_socks + + + + 0 + 6 + 1 + 1 + + + + + True + False + 0 + WPAD warning... + True + 50 + + + 0 + 7 + 3 + 1 + + + + + True + True + + True + + + 1 + 3 + 1 + 1 + + + + + True + True + + 1 + True + adjustment_proxy_port_http + + + 2 + 3 + 1 + 1 + + + + + True + True + + True + + + 1 + 4 + 1 + 1 + + + + + True + True + + True + + + 1 + 5 + 1 + 1 + + + + + True + True + + True + + + 1 + 6 + 1 + 1 + + + + + True + True + + 1 + True + adjustment_proxy_port_https + + + 2 + 4 + 1 + 1 + + + + + True + True + + 1 + True + adjustment_proxy_port_ftp + + + 2 + 5 + 1 + 1 + + + + + True + True + + 1 + True + adjustment_proxy_port_socks + + + 2 + 6 + 1 + 1 + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/configure.ac gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/configure.ac --- gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,542 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.0 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/bluetooth-properties.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/cc-power-panel.c gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/cc-power-panel.c --- gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/cc-power-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/cc-power-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1125 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2010 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include + +#include "cc-power-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcPowerPanel, cc_power_panel) + +#define POWER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_POWER_PANEL, CcPowerPanelPrivate)) + +struct _CcPowerPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + UpClient *up_client; + GtkWidget *levelbar_primary; +}; + +enum +{ + ACTION_MODEL_TEXT, + ACTION_MODEL_VALUE, + ACTION_MODEL_SENSITIVE +}; + +static void +cc_power_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_dispose (GObject *object) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (object)->priv; + + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + if (priv->up_client != NULL) + { + g_object_unref (priv->up_client); + priv->up_client = NULL; + } + + G_OBJECT_CLASS (cc_power_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcPowerPanel *panel) +{ +} + +static const char * +cc_power_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/power"; + else + return "help:gnome-help/power"; +} + +static void +cc_power_panel_class_init (CcPowerPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcPowerPanelPrivate)); + + object_class->get_property = cc_power_panel_get_property; + object_class->set_property = cc_power_panel_set_property; + object_class->dispose = cc_power_panel_dispose; + + panel_class->get_help_uri = cc_power_panel_get_help_uri; +} + +static gchar * +get_timestring (guint64 time_secs) +{ + gchar* timestring = NULL; + gint hours; + gint minutes; + + /* Add 0.5 to do rounding */ + minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); + + if (minutes == 0) + { + timestring = g_strdup (_("Unknown time")); + return timestring; + } + + if (minutes < 60) + { + timestring = g_strdup_printf (ngettext ("%i minute", + "%i minutes", + minutes), minutes); + return timestring; + } + + hours = minutes / 60; + minutes = minutes % 60; + + if (minutes == 0) + { + timestring = g_strdup_printf (ngettext ( + "%i hour", + "%i hours", + hours), hours); + return timestring; + } + + /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" + * Swap order with "%2$s %2$i %1$s %1$i if needed */ + timestring = g_strdup_printf (_("%i %s %i %s"), + hours, ngettext ("hour", "hours", hours), + minutes, ngettext ("minute", "minutes", minutes)); + return timestring; +} + +static void +set_device_battery_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* clear the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_hide (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Charging - %s until fully charged"), + time_string); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low battery, %s remaining"), + time_string); + /* show the warning */ + gtk_widget_show (widget); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using battery power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Using battery power")); + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Empty")); + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device until we stumble upon the device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_ups_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* always show the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_show (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low UPS, %s remaining"), + time_string); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using UPS power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Caution low UPS")); + } + else + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Using UPS power")); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device as extra UPS devices are not possible */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_battery_additional (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + GtkWidget *widget; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + NULL, /* percentage */ + &state, + NULL /* time */); + + /* set the description */ + switch (state) + { + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is empty")); + break; + default: + break; + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_addon")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the addon device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_show (widget); +out: + g_free (details); +} + +static void +add_device_secondary (CcPowerPanel *panel, + GVariant *device, + guint *secondary_devices_cnt) +{ + CcPowerPanelPrivate *priv = panel->priv; + const gchar *icon_name = NULL; + gdouble percentage; + guint64 time; + UpDeviceKind kind; + UpDeviceState state; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *widget; + GString *status; + GString *description; + gboolean show_caution = FALSE; + + g_variant_get (device, + "(susdut)", + NULL, + &kind, + NULL, + &percentage, + &state, + &time); + + switch (kind) + { + case UP_DEVICE_KIND_UPS: + icon_name = "uninterruptible-power-supply"; + show_caution = TRUE; + break; + case UP_DEVICE_KIND_MOUSE: + icon_name = "input-mouse"; + break; + case UP_DEVICE_KIND_KEYBOARD: + icon_name = "input-keyboard"; + break; + case UP_DEVICE_KIND_TABLET: + icon_name = "input-tablet"; + break; + case UP_DEVICE_KIND_PDA: + icon_name = "pda"; + break; + case UP_DEVICE_KIND_PHONE: + icon_name = "phone"; + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + icon_name = "multimedia-player"; + break; + case UP_DEVICE_KIND_COMPUTER: + icon_name = "computer"; + show_caution = TRUE; + break; + default: + icon_name = "battery"; + break; + } + + switch (kind) + { + case UP_DEVICE_KIND_MOUSE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless mouse")); + break; + case UP_DEVICE_KIND_KEYBOARD: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless keyboard")); + break; + case UP_DEVICE_KIND_UPS: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Uninterruptible power supply")); + break; + case UP_DEVICE_KIND_PDA: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Personal digital assistant")); + break; + case UP_DEVICE_KIND_PHONE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Cellphone")); + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Media player")); + break; + case UP_DEVICE_KIND_TABLET: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Tablet")); + break; + case UP_DEVICE_KIND_COMPUTER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Computer")); + break; + default: + /* TRANSLATORS: secondary battery, misc */ + description = g_string_new (_("Battery")); + break; + } + g_string_prepend (description, ""); + g_string_append (description, ""); + + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: secondary battery */ + status = g_string_new(C_("Battery power", "Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 10 && show_caution) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Caution")); + } + else if (percentage < 30) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Low")); + } + else + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Good")); + } + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Empty")); + break; + default: + status = g_string_new (up_device_state_to_string (state)); + break; + } + g_string_prepend (status, ""); + g_string_append (status, ""); + + /* create the new widget */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_widget_set_hexpand (hbox, TRUE); + widget = gtk_image_new (); + gtk_misc_set_alignment (GTK_MISC (widget), 0.5f, 0.0f); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_DND); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), description->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), status->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_level_bar_new (); + gtk_widget_set_margin_right (widget, 32); + gtk_widget_set_margin_top (widget, 3); + gtk_level_bar_set_value (GTK_LEVEL_BAR (widget), percentage / 100.0f); + gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + /* add to the grid */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + + /* two devices wide */ + gtk_grid_attach (GTK_GRID (widget), hbox, + *secondary_devices_cnt % 2, + (*secondary_devices_cnt / 2) - 1, + 1, 1); + (*secondary_devices_cnt)++; + + /* show panel */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_show_all (widget); + + g_string_free (description, TRUE); + g_string_free (status, TRUE); +} + +static void +get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + CcPowerPanel *panel; + CcPowerPanelPrivate *priv; + gboolean got_primary = FALSE; + gboolean ups_as_primary_device = FALSE; + GError *error = NULL; + gsize n_devices; + GList *children; + GList *l; + GtkWidget *widget; + guint i; + guint secondary_devices_cnt = 0; + GVariant *child; + GVariant *result; + GVariant *untuple; + UpDeviceKind kind; + UpDeviceState state; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; /* Must exit before accessing freed memory */ + } + + panel = CC_POWER_PANEL (user_data); + priv = panel->priv; + + /* empty the secondary box */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (widget), l->data); + g_list_free (children); + + /* hide both panels initially */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_hide (widget); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_hide (widget); + + if (result == NULL) + { + g_printerr ("Error getting devices: %s\n", error->message); + g_error_free (error); + return; + } + + untuple = g_variant_get_child_value (result, 0); + n_devices = g_variant_n_children (untuple); + + /* first we look for a discharging UPS, which is promoted to the + * primary device if it's discharging. Otherwise we use the first + * listed laptop battery as the primary device */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + &state, + NULL); + if (kind == UP_DEVICE_KIND_UPS && + state == UP_DEVICE_STATE_DISCHARGING) + { + ups_as_primary_device = TRUE; + } + g_variant_unref (child); + } + + /* add the devices now we know the state-of-play */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + NULL, + NULL); + if (kind == UP_DEVICE_KIND_LINE_POWER) + { + /* do nothing */ + } + else if (kind == UP_DEVICE_KIND_UPS && ups_as_primary_device) + { + set_device_ups_primary (panel, child); + } + else if (kind == UP_DEVICE_KIND_BATTERY && !ups_as_primary_device) + { + if (!got_primary) + { + set_device_battery_primary (panel, child); + got_primary = TRUE; + } + else + { + set_device_battery_additional (panel, child); + } + } + else + { + add_device_secondary (panel, child, &secondary_devices_cnt); + } + g_variant_unref (child); + } + + g_variant_unref (untuple); + g_variant_unref (result); +} + +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (user_data)->priv; + + /* get the new state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GDBusProxy *proxy; + CcPowerPanelPrivate *priv; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* Access user_data after checking for error because user_data might be + disposed already. */ + priv = CC_POWER_PANEL (user_data)->priv; + priv->proxy = proxy; + + /* we want to change the primary device changes */ + g_signal_connect (priv->proxy, + "g-properties-changed", + G_CALLBACK (on_properties_changed), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly expand the dialog */ + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +combo_time_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both keys */ + g_settings_set_int (self->priv->gsd_settings, key, value); +} + +static void +combo_enum_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_enum (self->priv->gsd_settings, key, value); +} + +static void +disable_unavailable_combo_items (CcPowerPanel *self, + GtkComboBox *combo_box) +{ + gboolean enabled; + gboolean ret; + gint value_tmp; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkTreeModel *model; + + /* setup the renderer */ + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", ACTION_MODEL_TEXT, + "sensitive", ACTION_MODEL_SENSITIVE, + NULL); + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* disable any actions we cannot do */ + do + { + gtk_tree_model_get (model, &iter, + ACTION_MODEL_VALUE, &value_tmp, + -1); + switch (value_tmp) { + case GSD_POWER_ACTION_SUSPEND: + enabled = up_client_get_can_suspend (self->priv->up_client); + break; + case GSD_POWER_ACTION_HIBERNATE: + enabled = up_client_get_can_hibernate (self->priv->up_client); + break; + default: + enabled = TRUE; + } + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + ACTION_MODEL_SENSITIVE, enabled, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_value_for_combo (GtkComboBox *combo_box, gint value) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value_tmp; + gboolean ret; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* try to make the UI match the setting */ + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_ac_battery_ui_mode (CcPowerPanel *self) +{ + gboolean has_batteries = FALSE; + gboolean has_lid = FALSE; + gboolean ret; + GError *error = NULL; + GPtrArray *devices; + guint i; + UpDevice *device; + UpDeviceKind kind; + CcPowerPanelPrivate *priv = self->priv; + + /* this is sync, but it's cached in the daemon and so quick */ + ret = up_client_enumerate_devices_sync (self->priv->up_client, NULL, &error); + if (!ret) + { + g_warning ("failed to get device list: %s", error->message); + g_error_free (error); + goto out; + } + + devices = up_client_get_devices (self->priv->up_client); + for (i=0; ilen; i++) + { + device = g_ptr_array_index (devices, i); + g_object_get (device, + "kind", &kind, + NULL); + if (kind == UP_DEVICE_KIND_BATTERY || + kind == UP_DEVICE_KIND_UPS) + { + has_batteries = TRUE; + break; + } + } + g_ptr_array_unref (devices); + + has_lid = up_client_get_lid_is_present (self->priv->up_client); + +out: + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_ac"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_lid_action"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_battery"), has_batteries && has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_critical"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_critical"), has_batteries); +} + +static gboolean +activate_link_cb (GtkLabel *label, gchar *uri, CcPowerPanel *self) +{ + CcShell *shell; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, uri, NULL, &error) == FALSE) + { + g_warning ("Failed to activate %s panel: %s", uri, error->message); + g_error_free (error); + } + return TRUE; +} + +static void +cc_power_panel_init (CcPowerPanel *self) +{ + GError *error; + GtkWidget *widget; + gint value; + char *text; + + self->priv = POWER_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/power.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + /* add levelbar */ + self->priv->levelbar_primary = GTK_WIDGET + (gtk_builder_get_object (self->priv->builder, "levelbar_primary")); + self->priv->cancellable = g_cancellable_new (); + + /* get initial icon state */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power", + self->priv->cancellable, + got_power_proxy_cb, + self); + + /* find out if there are any battery or UPS devices attached + * and setup UI accordingly */ + self->priv->up_client = up_client_new (); + set_ac_battery_ui_mode (self); + + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + g_signal_connect (self->priv->gsd_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + + /* auto-sleep time */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-ac-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_ac")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-ac-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-battery-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_battery")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-battery-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + + /* actions */ + value = g_settings_get_enum (self->priv->gsd_settings, "critical-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_critical")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "critical-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + /* set screen link */ + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "label_screen_settings")); + /* TRANSLATORS: this is a link to the "Brightness and Lock" control center panel */ + text = g_strdup_printf ("%s", + _("Tip: screen brightness affects how much power is used")); + gtk_label_set_markup (GTK_LABEL (widget), text); + g_free (text); + + g_signal_connect (widget, "activate-link", + G_CALLBACK (activate_link_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-ac-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_ac")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-ac-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_battery")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + widget = WID (self->priv->builder, "vbox_power"); + gtk_widget_reparent (widget, (GtkWidget *) self); +} + +void +cc_power_panel_register (GIOModule *module) +{ + cc_power_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_POWER_PANEL, + "power", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/power.ui gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/power.ui --- gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/power.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/97_unity_power_ui.patch/panels/power/power.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + Hibernate + 3 + True + + + Power off + 2 + True + + + + + + + + + + + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + Don't suspend + 0 + + + + + + + + + + + + + + + Suspend + 1 + True + + + Do nothing + 5 + True + + + + + False + False + + + True + False + 12 + 3 + + + True + False + 53 + 60 + 24 + vertical + 6 + 12 + + + True + False + On battery power + center + + + + + + 1 + 0 + + + + + True + False + When plugged in + center + + + + + + 2 + 0 + + + + + True + False + end + Suspend when inactive for + + + 0 + 1 + + + + + True + False + liststore_time + True + + + + + + + 1 + 1 + + + + + 150 + True + False + liststore_time + True + + + + + + + 2 + 1 + + + + + True + False + end + When power is _critically low + True + combobox_critical + + + 0 + 2 + + + + + True + False + liststore_critical + + + 1 + 2 + + + + + True + False + end + When the lid is closed + + + 0 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 1 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 2 + 3 + + + + + False + False + 0 + + + + + True + False + 53 + 60 + vertical + 3 + + + True + False + 3 + + + True + False + dialog-warning-symbolic + + + False + True + 0 + + + + + True + False + 0 + 55 minutes until fully charged + + + True + True + 1 + + + + + True + False + 3 + + + True + False + 1 + gtk-info + + + False + True + 0 + + + + + True + False + 1 + Your secondary battery is empty + + + False + True + 1 + + + + + False + False + 2 + + + + + False + True + 0 + + + + + False + True + + + False + True + 1 + + + + + False + False + 1 + + + + + True + False + 53 + 40 + 0 + 0.49000000953674316 + 4 + Tip: <a href="moo">Screen Settings</a> affect how much power is used + True + False + + + False + False + 2 + + + + + True + False + 15 + vertical + 24 + + + True + False + + + False + True + 0 + + + + + True + False + 9 + 28 + 15 + 18 + 6 + True + + + + + + + + + False + True + 1 + + + + + False + False + 3 + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/98_default_sound_theme.patch/panels/sound/gvc-sound-theme-chooser.c gnome-control-center-3.6.3/.pc/98_default_sound_theme.patch/panels/sound/gvc-sound-theme-chooser.c --- gnome-control-center-3.6.3/.pc/98_default_sound_theme.patch/panels/sound/gvc-sound-theme-chooser.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/98_default_sound_theme.patch/panels/sound/gvc-sound-theme-chooser.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,833 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Bastien Nocera + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "gvc-sound-theme-chooser.h" +#include "sound-theme-file-utils.h" + +#define GVC_SOUND_THEME_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserPrivate)) + +struct GvcSoundThemeChooserPrivate +{ + GtkWidget *treeview; + GtkWidget *selection_box; + GSettings *settings; + GSettings *sound_settings; + char *current_theme; + char *current_parent; +}; + +static void gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass); +static void gvc_sound_theme_chooser_init (GvcSoundThemeChooser *sound_theme_chooser); +static void gvc_sound_theme_chooser_finalize (GObject *object); + +G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_VBOX) + +#define KEY_SOUNDS_SCHEMA "org.gnome.desktop.sound" +#define EVENT_SOUNDS_KEY "event-sounds" +#define INPUT_SOUNDS_KEY "input-feedback-sounds" +#define SOUND_THEME_KEY "theme-name" + +#define WM_SCHEMA "org.gnome.desktop.wm.preferences" +#define AUDIO_BELL_KEY "audible-bell" + +#define DEFAULT_ALERT_ID "__default" +#define CUSTOM_THEME_NAME "__custom" +#define NO_SOUNDS_THEME_NAME "__no_sounds" +#define DEFAULT_THEME "freedesktop" + +enum { + THEME_DISPLAY_COL, + THEME_IDENTIFIER_COL, + THEME_PARENT_ID_COL, + THEME_NUM_COLS +}; + +enum { + ALERT_DISPLAY_COL, + ALERT_IDENTIFIER_COL, + ALERT_SOUND_TYPE_COL, + ALERT_NUM_COLS +}; + +enum { + SOUND_TYPE_UNSET, + SOUND_TYPE_OFF, + SOUND_TYPE_DEFAULT_FROM_THEME, + SOUND_TYPE_BUILTIN, + SOUND_TYPE_CUSTOM +}; + +#define GVC_SOUND_SOUND (xmlChar *) "sound" +#define GVC_SOUND_NAME (xmlChar *) "name" +#define GVC_SOUND_FILENAME (xmlChar *) "filename" + +/* Adapted from yelp-toc-pager.c */ +static xmlChar * +xml_get_and_trim_names (xmlNodePtr node) +{ + xmlNodePtr cur; + xmlChar *keep_lang = NULL; + xmlChar *value; + int j, keep_pri = INT_MAX; + + const gchar * const * langs = g_get_language_names (); + + value = NULL; + + for (cur = node->children; cur; cur = cur->next) { + if (! xmlStrcmp (cur->name, GVC_SOUND_NAME)) { + xmlChar *cur_lang = NULL; + int cur_pri = INT_MAX; + + cur_lang = xmlNodeGetLang (cur); + + if (cur_lang) { + for (j = 0; langs[j]; j++) { + if (g_str_equal (cur_lang, langs[j])) { + cur_pri = j; + break; + } + } + } else { + cur_pri = INT_MAX - 1; + } + + if (cur_pri <= keep_pri) { + if (keep_lang) + xmlFree (keep_lang); + if (value) + xmlFree (value); + + value = xmlNodeGetContent (cur); + + keep_lang = cur_lang; + keep_pri = cur_pri; + } else { + if (cur_lang) + xmlFree (cur_lang); + } + } + } + + /* Delete all GVC_SOUND_NAME nodes */ + cur = node->children; + while (cur) { + xmlNodePtr this = cur; + cur = cur->next; + if (! xmlStrcmp (this->name, GVC_SOUND_NAME)) { + xmlUnlinkNode (this); + xmlFreeNode (this); + } + } + + return value; +} + +static void +populate_model_from_node (GvcSoundThemeChooser *chooser, + GtkTreeModel *model, + xmlNodePtr node) +{ + xmlNodePtr child; + xmlChar *filename; + xmlChar *name; + + filename = NULL; + name = xml_get_and_trim_names (node); + for (child = node->children; child; child = child->next) { + if (xmlNodeIsText (child)) { + continue; + } + + if (xmlStrcmp (child->name, GVC_SOUND_FILENAME) == 0) { + filename = xmlNodeGetContent (child); + } else if (xmlStrcmp (child->name, GVC_SOUND_NAME) == 0) { + /* EH? should have been trimmed */ + } + } + + if (filename != NULL && name != NULL) { + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), + NULL, + G_MAXINT, + ALERT_IDENTIFIER_COL, filename, + ALERT_DISPLAY_COL, name, + ALERT_SOUND_TYPE_COL, _("Built-in"), + -1); + } + + xmlFree (filename); + xmlFree (name); +} + +static void +populate_model_from_file (GvcSoundThemeChooser *chooser, + GtkTreeModel *model, + const char *filename) +{ + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr child; + gboolean exists; + + exists = g_file_test (filename, G_FILE_TEST_EXISTS); + if (! exists) { + return; + } + + doc = xmlParseFile (filename); + if (doc == NULL) { + return; + } + + root = xmlDocGetRootElement (doc); + + for (child = root->children; child; child = child->next) { + if (xmlNodeIsText (child)) { + continue; + } + if (xmlStrcmp (child->name, GVC_SOUND_SOUND) != 0) { + continue; + } + + populate_model_from_node (chooser, model, child); + } + + xmlFreeDoc (doc); +} + +static void +populate_model_from_dir (GvcSoundThemeChooser *chooser, + GtkTreeModel *model, + const char *dirname) +{ + GDir *d; + const char *name; + + d = g_dir_open (dirname, 0, NULL); + if (d == NULL) { + return; + } + + while ((name = g_dir_read_name (d)) != NULL) { + char *path; + + if (! g_str_has_suffix (name, ".xml")) { + continue; + } + + path = g_build_filename (dirname, name, NULL); + populate_model_from_file (chooser, model, path); + g_free (path); + } +} + +static gboolean +save_alert_sounds (GvcSoundThemeChooser *chooser, + const char *id) +{ + const char *sounds[3] = { "bell-terminal", "bell-window-system", NULL }; + char *path; + + if (strcmp (id, DEFAULT_ALERT_ID) == 0) { + delete_old_files (sounds); + delete_disabled_files (sounds); + } else { + delete_old_files (sounds); + delete_disabled_files (sounds); + add_custom_file (sounds, id); + } + + /* And poke the directory so the theme gets updated */ + path = custom_theme_dir_path (NULL); + if (utime (path, NULL) != 0) { + g_warning ("Failed to update mtime for directory '%s': %s", + path, g_strerror (errno)); + } + g_free (path); + + return FALSE; +} + + +static void +update_alert_model (GvcSoundThemeChooser *chooser, + const char *id) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); + gtk_tree_model_get_iter_first (model, &iter); + do { + char *this_id; + + gtk_tree_model_get (model, &iter, + ALERT_IDENTIFIER_COL, &this_id, + -1); + + if (strcmp (this_id, id) == 0) { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->priv->treeview)); + gtk_tree_selection_select_iter (selection, &iter); + } + + g_free (this_id); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +save_theme_name (GvcSoundThemeChooser *chooser, + const char *theme_name) +{ + /* If the name is empty, use "freedesktop" */ + if (theme_name == NULL || *theme_name == '\0') { + theme_name = DEFAULT_THEME; + } + + /* special case for no sounds */ + if (strcmp (theme_name, NO_SOUNDS_THEME_NAME) == 0) { + g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, FALSE); + return; + } else { + g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, TRUE); + } + + g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name); +} + +static gboolean +load_theme_file (const char *path, + char **parent) +{ + GKeyFile *file; + gboolean hidden; + + file = g_key_file_new (); + if (g_key_file_load_from_file (file, path, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) == FALSE) { + g_key_file_free (file); + return FALSE; + } + /* Don't add hidden themes to the list */ + hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL); + if (!hidden) { + /* Save the parent theme, if there's one */ + if (parent != NULL) { + *parent = g_key_file_get_string (file, + "Sound Theme", + "Inherits", + NULL); + } + } + + g_key_file_free (file); + + return TRUE; +} + +static gboolean +load_theme_name (const char *name, + char **parent) +{ + const char * const *data_dirs; + const char *data_dir; + char *path; + guint i; + gboolean res; + + data_dir = g_get_user_data_dir (); + path = g_build_filename (data_dir, "sounds", name, "index.theme", NULL); + res = load_theme_file (path, parent); + g_free (path); + if (res) + return TRUE; + + data_dirs = g_get_system_data_dirs (); + for (i = 0; data_dirs[i] != NULL; i++) { + path = g_build_filename (data_dirs[i], "sounds", name, "index.theme", NULL); + res = load_theme_file (path, parent); + g_free (path); + if (res) + return TRUE; + } + + return FALSE; +} + +static void +update_alert (GvcSoundThemeChooser *chooser, + const char *alert_id) +{ + gboolean is_custom; + gboolean is_default; + gboolean add_custom; + gboolean remove_custom; + + is_custom = strcmp (chooser->priv->current_theme, CUSTOM_THEME_NAME) == 0; + is_default = strcmp (alert_id, DEFAULT_ALERT_ID) == 0; + + /* So a few possibilities: + * 1. Named theme, default alert selected: noop + * 2. Named theme, alternate alert selected: create new custom with sound + * 3. Custom theme, default alert selected: remove sound and possibly custom + * 4. Custom theme, alternate alert selected: update custom sound + */ + add_custom = FALSE; + remove_custom = FALSE; + if (! is_custom && is_default) { + /* remove custom just in case */ + remove_custom = TRUE; + } else if (! is_custom && ! is_default) { + if (chooser->priv->current_parent) + create_custom_theme (chooser->priv->current_parent); + else + create_custom_theme (DEFAULT_THEME); + save_alert_sounds (chooser, alert_id); + add_custom = TRUE; + } else if (is_custom && is_default) { + save_alert_sounds (chooser, alert_id); + /* after removing files check if it is empty */ + if (custom_theme_dir_is_empty ()) { + remove_custom = TRUE; + } + } else if (is_custom && ! is_default) { + save_alert_sounds (chooser, alert_id); + } + + if (add_custom) { + save_theme_name (chooser, CUSTOM_THEME_NAME); + } else if (remove_custom) { + delete_custom_theme_dir (); + if (is_custom) { + save_theme_name (chooser, chooser->priv->current_parent); + } + } + + update_alert_model (chooser, alert_id); +} + +static void +play_preview_for_id (GvcSoundThemeChooser *chooser, + const char *id) +{ + g_return_if_fail (id != NULL); + + /* special case: for the default item on custom themes + * play the alert for the parent theme */ + if (strcmp (id, DEFAULT_ALERT_ID) == 0) { + if (chooser->priv->current_parent != NULL) { + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), + CA_PROP_EVENT_ID, "bell-window-system", + CA_PROP_CANBERRA_XDG_THEME_NAME, chooser->priv->current_parent, + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), + CA_PROP_CANBERRA_CACHE_CONTROL, "never", + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", +#ifdef CA_PROP_CANBERRA_ENABLE + CA_PROP_CANBERRA_ENABLE, "1", +#endif + NULL); + } else { + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), + CA_PROP_EVENT_ID, "bell-window-system", + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), + CA_PROP_CANBERRA_CACHE_CONTROL, "never", + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", +#ifdef CA_PROP_CANBERRA_ENABLE + CA_PROP_CANBERRA_ENABLE, "1", +#endif + NULL); + } + } else { + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), + CA_PROP_MEDIA_FILENAME, id, + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), + CA_PROP_CANBERRA_CACHE_CONTROL, "never", + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", +#ifdef CA_PROP_CANBERRA_ENABLE + CA_PROP_CANBERRA_ENABLE, "1", +#endif + NULL); + + } +} + +static void +on_treeview_selection_changed (GtkTreeSelection *selection, + GvcSoundThemeChooser *chooser) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id; + + if (chooser->priv->treeview == NULL) { + return; + } + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) { + return; + } + + id = NULL; + gtk_tree_model_get (model, &iter, + ALERT_IDENTIFIER_COL, &id, + -1); + if (id == NULL) { + return; + } + + play_preview_for_id (chooser, id); + update_alert (chooser, id); + g_free (id); +} + +static gboolean +on_treeview_button_pressed (GtkTreeView *treeview, + GdkEventButton *event, + GvcSoundThemeChooser *chooser) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + + selection = gtk_tree_view_get_selection (treeview); + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview), + event->x, event->y, &path, NULL, NULL, NULL) == FALSE) { + return FALSE; + } + + if (gtk_tree_selection_path_is_selected (selection, path) == FALSE) { + gtk_tree_path_free (path); + return FALSE; + } + gtk_tree_path_free (path); + + on_treeview_selection_changed (selection, chooser); + + return FALSE; +} + +static GtkWidget * +create_alert_treeview (GvcSoundThemeChooser *chooser) +{ + GtkListStore *store; + GtkWidget *treeview; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + treeview = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); + g_signal_connect (treeview, + "button-press-event", + G_CALLBACK (on_treeview_button_pressed), + chooser); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + g_signal_connect (selection, + "changed", + G_CALLBACK (on_treeview_selection_changed), + chooser); + + /* Setup the tree model, 3 columns: + * - display name + * - sound id + * - sound type + */ + store = gtk_list_store_new (ALERT_NUM_COLS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_list_store_insert_with_values (store, + NULL, + G_MAXINT, + ALERT_IDENTIFIER_COL, DEFAULT_ALERT_ID, + ALERT_DISPLAY_COL, _("Default"), + ALERT_SOUND_TYPE_COL, _("From theme"), + -1); + + populate_model_from_dir (chooser, GTK_TREE_MODEL (store), SOUND_SET_DIR); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), + GTK_TREE_MODEL (store)); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Name"), + renderer, + "text", ALERT_DISPLAY_COL, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + return treeview; +} + +static int +get_file_type (const char *sound_name, + char **linked_name) +{ + char *name, *filename; + + *linked_name = NULL; + + name = g_strdup_printf ("%s.disabled", sound_name); + filename = custom_theme_dir_path (name); + g_free (name); + + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) { + g_free (filename); + return SOUND_TYPE_OFF; + } + g_free (filename); + + /* We only check for .ogg files because those are the + * only ones we create */ + name = g_strdup_printf ("%s.ogg", sound_name); + filename = custom_theme_dir_path (name); + g_free (name); + + if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK) != FALSE) { + *linked_name = g_file_read_link (filename, NULL); + g_free (filename); + return SOUND_TYPE_CUSTOM; + } + g_free (filename); + + return SOUND_TYPE_BUILTIN; +} + +static void +update_alerts_from_theme_name (GvcSoundThemeChooser *chooser, + const char *name) +{ + if (strcmp (name, CUSTOM_THEME_NAME) != 0) { + /* reset alert to default */ + update_alert (chooser, DEFAULT_ALERT_ID); + } else { + int sound_type; + char *linkname; + + linkname = NULL; + sound_type = get_file_type ("bell-terminal", &linkname); + g_debug ("Found link: %s", linkname); + if (sound_type == SOUND_TYPE_CUSTOM) { + update_alert (chooser, linkname); + } + } +} + +static void +update_theme (GvcSoundThemeChooser *chooser) +{ + gboolean events_enabled; + char *last_theme; + + events_enabled = g_settings_get_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY); + + last_theme = chooser->priv->current_theme; + if (events_enabled) { + chooser->priv->current_theme = g_settings_get_string (chooser->priv->sound_settings, SOUND_THEME_KEY); + } else { + chooser->priv->current_theme = g_strdup (NO_SOUNDS_THEME_NAME); + } + + if (g_strcmp0 (last_theme, chooser->priv->current_theme) != 0) { + g_free (chooser->priv->current_parent); + if (load_theme_name (chooser->priv->current_theme, + &chooser->priv->current_parent) == FALSE) { + g_free (chooser->priv->current_theme); + chooser->priv->current_theme = g_strdup (DEFAULT_THEME); + load_theme_name (DEFAULT_THEME, + &chooser->priv->current_parent); + } + } + g_free (last_theme); + + gtk_widget_set_sensitive (chooser->priv->selection_box, events_enabled); + + update_alerts_from_theme_name (chooser, chooser->priv->current_theme); +} + +static GObject * +gvc_sound_theme_chooser_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + GvcSoundThemeChooser *self; + + object = G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->constructor (type, n_construct_properties, construct_params); + + self = GVC_SOUND_THEME_CHOOSER (object); + + update_theme (self); + + return object; +} + +static void +gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = gvc_sound_theme_chooser_constructor; + object_class->finalize = gvc_sound_theme_chooser_finalize; + + g_type_class_add_private (klass, sizeof (GvcSoundThemeChooserPrivate)); +} + +static void +on_sound_settings_changed (GSettings *settings, + const char *key, + GvcSoundThemeChooser *chooser) +{ + if (strcmp (key, EVENT_SOUNDS_KEY) == 0) { + update_theme (chooser); + } else if (strcmp (key, SOUND_THEME_KEY) == 0) { + update_theme (chooser); + } else if (strcmp (key, INPUT_SOUNDS_KEY) == 0) { + update_theme (chooser); + } +} + +static void +on_audible_bell_changed (GSettings *settings, + const char *key, + GvcSoundThemeChooser *chooser) +{ + update_theme (chooser); +} + +static void +setup_list_size_constraint (GtkWidget *widget, + GtkWidget *to_size) +{ + GtkRequisition req; + int max_height; + + /* constrain height to be the tree height up to a max */ + max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget))) / 4; + + gtk_widget_get_preferred_size (to_size, NULL, &req); + + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), + MIN (req.height, max_height)); +} + +static void +gvc_sound_theme_chooser_init (GvcSoundThemeChooser *chooser) +{ + GtkWidget *box; + GtkWidget *label; + GtkWidget *scrolled_window; + GtkWidget *alignment; + char *str; + + chooser->priv = GVC_SOUND_THEME_CHOOSER_GET_PRIVATE (chooser); + + chooser->priv->settings = g_settings_new (WM_SCHEMA); + chooser->priv->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA); + + str = g_strdup_printf ("%s", _("C_hoose an alert sound:")); + chooser->priv->selection_box = box = gtk_frame_new (str); + g_free (str); + label = gtk_frame_get_label_widget (GTK_FRAME (box)); + gtk_label_set_use_underline (GTK_LABEL (label), TRUE); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); + + alignment = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); + gtk_container_add (GTK_CONTAINER (alignment), box); + gtk_box_pack_start (GTK_BOX (chooser), alignment, TRUE, TRUE, 6); + + alignment = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); + gtk_container_add (GTK_CONTAINER (box), alignment); + + chooser->priv->treeview = create_alert_treeview (chooser); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->treeview); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + setup_list_size_constraint (scrolled_window, chooser->priv->treeview); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (scrolled_window), chooser->priv->treeview); + gtk_container_add (GTK_CONTAINER (alignment), scrolled_window); + + g_signal_connect (G_OBJECT (chooser->priv->sound_settings), "changed", + G_CALLBACK (on_sound_settings_changed), chooser); + g_signal_connect (chooser->priv->settings, "changed::" AUDIO_BELL_KEY, + G_CALLBACK (on_audible_bell_changed), chooser); +} + +static void +gvc_sound_theme_chooser_finalize (GObject *object) +{ + GvcSoundThemeChooser *sound_theme_chooser; + + g_return_if_fail (object != NULL); + g_return_if_fail (GVC_IS_SOUND_THEME_CHOOSER (object)); + + sound_theme_chooser = GVC_SOUND_THEME_CHOOSER (object); + + if (sound_theme_chooser->priv != NULL) { + g_object_unref (sound_theme_chooser->priv->settings); + g_object_unref (sound_theme_chooser->priv->sound_settings); + } + + G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->finalize (object); +} + +GtkWidget * +gvc_sound_theme_chooser_new (void) +{ + GObject *chooser; + chooser = g_object_new (GVC_TYPE_SOUND_THEME_CHOOSER, + "spacing", 6, + NULL); + return GTK_WIDGET (chooser); +} diff -Nru gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/cc-screen-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/cc-screen-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,566 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "cc-screen-panel.h" + +CC_PANEL_REGISTER (CcScreenPanel, cc_screen_panel) + +#define SCREEN_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SCREEN_PANEL, CcScreenPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +struct _CcScreenPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *session_settings; + GSettings *lockdown_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + gboolean setting_brightness; +}; + + +static void +cc_screen_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_dispose (GObject *object) +{ + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (object)->priv; + + if (priv->lock_settings) + { + g_object_unref (priv->lock_settings); + priv->lock_settings = NULL; + } + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->session_settings) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + G_OBJECT_CLASS (cc_screen_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "lock-delay") == FALSE) + return; +} + +static void +update_lock_screen_sensitivity (CcScreenPanel *self) +{ + GtkWidget *widget; + gboolean locked; + + widget = WID ("screen_lock_main_box"); + locked = g_settings_get_boolean (self->priv->lockdown_settings, "disable-lock-screen"); + gtk_widget_set_sensitive (widget, !locked); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "disable-lock-screen") == FALSE) + return; + + update_lock_screen_sensitivity (panel); +} + +static const char * +cc_screen_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; +} + +static void +cc_screen_panel_class_init (CcScreenPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcScreenPanelPrivate)); + + object_class->get_property = cc_screen_panel_get_property; + object_class->set_property = cc_screen_panel_set_property; + object_class->dispose = cc_screen_panel_dispose; + + panel_class->get_help_uri = cc_screen_panel_get_help_uri; +} + +static void +set_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* not setting, so pay attention to changed signals */ + priv->setting_brightness = FALSE; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + g_printerr ("Error setting brightness: %s\n", error->message); + g_error_free (error); + return; + } +} + +static void +brightness_slider_value_changed_cb (GtkRange *range, gpointer user_data) +{ + guint percentage; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* do not loop */ + if (priv->setting_brightness) + return; + + priv->setting_brightness = TRUE; + + /* push this to g-p-m */ + percentage = (guint) gtk_range_get_value (range); + g_dbus_proxy_call (priv->proxy, + "SetPercentage", + g_variant_new ("(u)", + percentage), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + set_brightness_cb, + user_data); +} + +static void +get_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + guint brightness; + GtkRange *range; + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + /* We got cancelled, so we're probably exiting */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + gtk_widget_hide (WID ("screen_brightness_hscale")); + gtk_widget_hide (WID ("screen_auto_reduce_checkbutton")); + gtk_widget_hide (WID ("brightness-frame")); + g_object_set (G_OBJECT (WID ("turn-off-alignment")), "left-padding", 0, NULL); + + if (error->message && + strstr (error->message, "No backlight devices present") == NULL) + { + g_warning ("Error getting brightness: %s", error->message); + } + g_error_free (error); + return; + } + + /* set the slider */ + g_variant_get (result, + "(u)", + &brightness); + range = GTK_RANGE (WID ("screen_brightness_hscale")); + gtk_range_set_range (range, 0, 100); + gtk_range_set_increments (range, 1, 10); + gtk_range_set_value (range, brightness); + g_signal_connect (range, + "value-changed", + G_CALLBACK (brightness_slider_value_changed_cb), + user_data); + g_variant_unref (result); +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + if (g_strcmp0 (signal_name, "Changed") == 0) + { + /* changed, but ignoring */ + if (self->priv->setting_brightness) + return; + + /* retrieve the value again from g-s-d */ + g_dbus_proxy_call (self->priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + self->priv->cancellable, + get_brightness_cb, + user_data); + } +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (priv->proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* we want to change the bar if the user presses brightness buttons */ + g_signal_connect (priv->proxy, + "g-signal", + G_CALLBACK (on_signal), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + priv->cancellable, + get_brightness_cb, + user_data); +} + +static void +set_idle_delay_from_dpms (CcScreenPanel *self, + int value) +{ + guint off_delay; + + off_delay = 0; + + if (value > 0) + off_delay = (guint) value; + + g_settings_set (self->priv->session_settings, "idle-delay", "u", off_delay); +} + +static void +dpms_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); + g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + + set_idle_delay_from_dpms (self, value); +} + +static void +lock_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint delay; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &delay, + -1); + g_settings_set (self->priv->lock_settings, "lock-delay", "u", delay); +} + +static void +set_dpms_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the AC setting */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +set_lock_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the lock setting */ + g_settings_get (self->priv->lock_settings, "lock-delay", "u", &value); + + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +cc_screen_panel_init (CcScreenPanel *self) +{ + GError *error; + GtkWidget *widget; + + self->priv = SCREEN_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/screen.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->cancellable = g_cancellable_new (); + + /* get initial brightness version */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + self->priv->cancellable, + got_power_proxy_cb, + self); + + self->priv->lock_settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_signal_connect (self->priv->lock_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + self->priv->session_settings = g_settings_new ("org.gnome.desktop.session"); + self->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect (self->priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + /* bind the auto dim checkbox */ + widget = WID ("screen_auto_reduce_checkbutton"); + g_settings_bind (self->priv->gsd_settings, + "idle-dim-battery", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* display off time */ + widget = WID ("screen_brightness_combobox"); + set_dpms_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (dpms_combo_changed_cb), + self); + + /* bind the screen lock checkbox */ + widget = WID ("screen_lock_on_switch"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* lock time */ + widget = WID ("screen_lock_combobox"); + set_lock_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (lock_combo_changed_cb), + self); + + widget = WID ("screen_lock_hbox"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "sensitive", + G_SETTINGS_BIND_GET); + + widget = WID ("show_notifications_check"); + g_settings_bind (self->priv->lock_settings, + "show-notifications", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_hide (widget); + + update_lock_screen_sensitivity (self); + + widget = WID ("screen_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + g_object_set (self, "valign", GTK_ALIGN_START, NULL); +} + +void +cc_screen_panel_register (GIOModule *module) +{ + cc_screen_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SCREEN_PANEL, + "screen", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/screen.ui gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/screen.ui --- gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/screen.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/99_add_lock-on-suspend.patch/panels/screen/screen.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,414 @@ + + + + + + + + + + + + + Screen turns off + 0 + + + 30 seconds + 30 + + + 1 minute + 60 + + + 2 minutes + 120 + + + 3 minutes + 180 + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + + + + + + + + + + + 1 minute + 60 + + + 2 minutes + 120 + + + 3 minutes + 180 + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + Never + 0 + + + + + + + True + vertical + + + True + 10 + vertical + 12 + + + True + 0 + none + + + True + 6 + 12 + + + True + vertical + 6 + + + True + True + 0 + False + bottom + + + + + + True + True + 0 + + + + + _Dim screen to save power + True + True + False + False + True + True + + + False + True + 1 + + + + + + + + + True + False + Brightness + True + + + + + + + + False + True + 0 + + + + + True + False + 6 + 12 + + + True + False + 6 + + + True + False + 0 + _Turn screen off when inactive for: + True + screen_brightness_combobox + + + False + False + 0 + + + + + True + False + screen_brightness_liststore + + + False + False + 1 + + + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + + + True + False + + + True + True + + + + + + False + True + 0 + + + + + False + False + 0 + + + + + True + False + 6 + + + True + False + 0 + _Lock screen after: + True + screen_lock_combobox + + + False + False + 0 + + + + + True + lock_liststore + + + False + False + 1 + + + + + False + False + 1 + + + + + False + True + + + Don't lock when at home + True + True + False + False + 0 + True + + + True + True + 0 + + + + + Locations... + True + True + True + False + False + none + right + http://glade.gnome.org + + + False + True + 1 + + + + + True + True + 2 + + + + + True + False + + + True + True + 0 + Show _notifications when locked + True + + + True + True + 0 + + + + + True + True + 3 + + + + + + + + + True + False + Lock + True + + + + + + + + False + True + 2 + + + + + True + True + 0 + + + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/accounts_fix_unsetting_icon.patch/panels/user-accounts/um-user.c gnome-control-center-3.6.3/.pc/accounts_fix_unsetting_icon.patch/panels/user-accounts/um-user.c --- gnome-control-center-3.6.3/.pc/accounts_fix_unsetting_icon.patch/panels/user-accounts/um-user.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/accounts_fix_unsetting_icon.patch/panels/user-accounts/um-user.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,991 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2004-2005 James M. Cape . + * Copyright (C) 2007-2008 William Jon McCann + * Copyright (C) 2009 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _XOPEN_SOURCE + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "um-user.h" +#include "um-account-type.h" +#include "um-utils.h" + + + #define UM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_USER, UmUserClass)) + #define UM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_USER)) +#define UM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), UM_TYPE_USER, UmUserClass)) + +#define MAX_FILE_SIZE 65536 + +typedef struct { + uid_t uid; + gchar *user_name; + gchar *real_name; + gint account_type; + gint password_mode; + gchar *password_hint; + gchar *email; + gchar *language; + gchar *location; + guint64 login_frequency; + gchar *icon_file; + gboolean locked; + gboolean automatic_login; + gboolean system_account; + gboolean local_account; +} UserProperties; + +static void +user_properties_free (UserProperties *props) +{ + g_free (props->user_name); + g_free (props->real_name); + g_free (props->password_hint); + g_free (props->email); + g_free (props->language); + g_free (props->location); + g_free (props->icon_file); + g_free (props); +} + +static UserProperties * +user_properties_get (GDBusConnection *bus, + const gchar *object_path) +{ + GVariant *result; + GVariantIter *iter; + gchar *key; + GVariant *value; + UserProperties *props; + GError *error = NULL; + + result = g_dbus_connection_call_sync (bus, + "org.freedesktop.Accounts", + object_path, + "org.freedesktop.DBus.Properties", + "GetAll", + g_variant_new ("(s)", "org.freedesktop.Accounts.User"), + G_VARIANT_TYPE ("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!result) { + g_debug ("Error calling GetAll() when retrieving properties for %s: %s", object_path, error->message); + g_error_free (error); + return NULL; + } + + /* Add some defaults that may not be received from some AccountsService versions */ + props = g_new0 (UserProperties, 1); + props->local_account = TRUE; + + g_variant_get (result, "(a{sv})", &iter); + while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { + if (strcmp (key, "Uid") == 0) { + g_variant_get (value, "t", &props->uid); + } + else if (strcmp (key, "UserName") == 0) { + g_variant_get (value, "s", &props->user_name); + } + else if (strcmp (key, "RealName") == 0) { + g_variant_get (value, "s", &props->real_name); + } + else if (strcmp (key, "AccountType") == 0) { + g_variant_get (value, "i", &props->account_type); + } + else if (strcmp (key, "Email") == 0) { + g_variant_get (value, "s", &props->email); + } + else if (strcmp (key, "Language") == 0) { + g_variant_get (value, "s", &props->language); + } + else if (strcmp (key, "Location") == 0) { + g_variant_get (value, "s", &props->location); + } + else if (strcmp (key, "LoginFrequency") == 0) { + g_variant_get (value, "t", &props->login_frequency); + } + else if (strcmp (key, "IconFile") == 0) { + g_variant_get (value, "s", &props->icon_file); + } + else if (strcmp (key, "Locked") == 0) { + g_variant_get (value, "b", &props->locked); + } + else if (strcmp (key, "AutomaticLogin") == 0) { + g_variant_get (value, "b", &props->automatic_login); + } + else if (strcmp (key, "SystemAccount") == 0) { + g_variant_get (value, "b", &props->system_account); + } + else if (strcmp (key, "LocalAccount") == 0) { + g_variant_get (value, "b", &props->local_account); + } + else if (strcmp (key, "PasswordMode") == 0) { + g_variant_get (value, "i", &props->password_mode); + } + else if (strcmp (key, "PasswordHint") == 0) { + g_variant_get (value, "s", &props->password_hint); + } + else if (strcmp (key, "HomeDirectory") == 0) { + /* ignore */ + } + else if (strcmp (key, "Shell") == 0) { + /* ignore */ + } + else { + g_debug ("unhandled property %s", key); + } + } + + g_variant_iter_free (iter); + g_variant_unref (result); + + return props; +} + + +struct _UmUser { + GObject parent; + + GDBusConnection *bus; + GDBusProxy *proxy; + gchar *object_path; + + UserProperties *props; + + gchar *display_name; +}; + +typedef struct _UmUserClass +{ + GObjectClass parent_class; +} UmUserClass; + +enum { + CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void um_user_finalize (GObject *object); + +G_DEFINE_TYPE (UmUser, um_user, G_TYPE_OBJECT) + +static void +um_user_class_init (UmUserClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->finalize = um_user_finalize; + + signals[CHANGED] = g_signal_new ("changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + + +static void +um_user_init (UmUser *user) +{ +} + +static void +um_user_finalize (GObject *object) +{ + UmUser *user; + + user = UM_USER (object); + + g_free (user->display_name); + + g_object_unref (user->bus); + g_free (user->object_path); + + if (user->proxy != NULL) + g_object_unref (user->proxy); + + if (user->props != NULL) + user_properties_free (user->props); + + (*G_OBJECT_CLASS (um_user_parent_class)->finalize) (object); +} + +uid_t +um_user_get_uid (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), -1); + + return user->props->uid; +} + +const gchar * +um_user_get_real_name (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->real_name; +} + +const gchar * +um_user_get_display_name (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + if (user->display_name) + return user->display_name; + if (user->props->real_name && + *user->props->real_name != '\0') + return user->props->real_name; + + return user->props->user_name; +} + +const gchar * +um_user_get_user_name (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->user_name; +} + +gint +um_user_get_account_type (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), UM_ACCOUNT_TYPE_STANDARD); + + return user->props->account_type; +} + +gulong +um_user_get_login_frequency (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), 0); + + return user->props->login_frequency; +} + +gint +um_user_collate (UmUser *user1, + UmUser *user2) +{ + const char *str1; + const char *str2; + gulong num1; + gulong num2; + + g_return_val_if_fail (UM_IS_USER (user1), 0); + g_return_val_if_fail (UM_IS_USER (user2), 0); + + num1 = user1->props->login_frequency; + num2 = user2->props->login_frequency; + if (num1 > num2) { + return -1; + } + + if (num1 < num2) { + return 1; + } + + /* if login frequency is equal try names */ + if (user1->props->real_name != NULL) { + str1 = user1->props->real_name; + } else { + str1 = user1->props->user_name; + } + + if (user2->props->real_name != NULL) { + str2 = user2->props->real_name; + } else { + str2 = user2->props->user_name; + } + + if (str1 == NULL && str2 != NULL) { + return -1; + } + + if (str1 != NULL && str2 == NULL) { + return 1; + } + + if (str1 == NULL && str2 == NULL) { + return 0; + } + + return g_utf8_collate (str1, str2); +} + +static gboolean +check_user_file (const char *filename, + gssize max_file_size) +{ + struct stat fileinfo; + + if (max_file_size < 0) { + max_file_size = G_MAXSIZE; + } + + /* Exists/Readable? */ + if (stat (filename, &fileinfo) < 0) { + g_debug ("File does not exist"); + return FALSE; + } + + /* Is a regular file */ + if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) { + g_debug ("File is not a regular file"); + return FALSE; + } + + /* Size is kosher? */ + if (G_UNLIKELY (fileinfo.st_size > max_file_size)) { + g_debug ("File is too large"); + return FALSE; + } + + return TRUE; +} + +static GdkPixbuf * +frame_pixbuf (GdkPixbuf *source) +{ + GdkPixbuf *dest; + cairo_t *cr; + cairo_surface_t *surface; + guint w; + guint h; + int frame_width; + double radius; + + frame_width = 2; + + w = gdk_pixbuf_get_width (source) + frame_width * 2; + h = gdk_pixbuf_get_height (source) + frame_width * 2; + radius = w / 10; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + w, h); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + /* set up image */ + cairo_rectangle (cr, 0, 0, w, h); + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); + cairo_fill (cr); + + rounded_rectangle (cr, 1.0, 0.5, 0.5, radius, w - 1, h - 1); + cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3); + cairo_fill_preserve (cr); + + gdk_cairo_set_source_pixbuf (cr, source, frame_width, frame_width); + cairo_fill (cr); + + dest = gdk_pixbuf_get_from_surface (surface, 0, 0, w, h); + + cairo_destroy (cr); + + return dest; +} + +GdkPixbuf * +um_user_render_icon (UmUser *user, + gboolean with_frame, + gint icon_size) +{ + GdkPixbuf *pixbuf; + GdkPixbuf *framed; + gboolean res; + GError *error; + + g_return_val_if_fail (UM_IS_USER (user), NULL); + g_return_val_if_fail (icon_size > 12, NULL); + + pixbuf = NULL; + if (user->props->icon_file) { + res = check_user_file (user->props->icon_file, + MAX_FILE_SIZE); + if (res) { + pixbuf = gdk_pixbuf_new_from_file_at_size (user->props->icon_file, + icon_size, + icon_size, + NULL); + } + else { + pixbuf = NULL; + } + } + + if (pixbuf != NULL) { + goto out; + } + + error = NULL; + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + + "avatar-default", + icon_size, + GTK_ICON_LOOKUP_FORCE_SIZE, + &error); + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } + + out: + + if (pixbuf != NULL && with_frame) { + framed = frame_pixbuf (pixbuf); + if (framed != NULL) { + g_object_unref (pixbuf); + pixbuf = framed; + } + } + + return pixbuf; +} + +const gchar * +um_user_get_email (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->email; +} + +const gchar * +um_user_get_language (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + if (*user->props->language == '\0') + return NULL; + return user->props->language; +} + +const gchar * +um_user_get_location (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->location; +} + +gint +um_user_get_password_mode (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), UM_PASSWORD_MODE_NONE); + + return user->props->password_mode; +} + +const char * +um_user_get_password_hint (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->password_hint; +} + +const char * +um_user_get_icon_file (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->props->icon_file; +} + +gboolean +um_user_get_locked (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), FALSE); + + return user->props->locked; +} +gboolean +um_user_get_automatic_login (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), FALSE); + + return user->props->automatic_login; +} + +gboolean +um_user_is_system_account (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), FALSE); + + return user->props->system_account; +} + +gboolean +um_user_is_local_account (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), FALSE); + + return user->props->local_account; +} + +const gchar * +um_user_get_object_path (UmUser *user) +{ + g_return_val_if_fail (UM_IS_USER (user), NULL); + + return user->object_path; +} + +static gboolean +update_info (UmUser *user) +{ + UserProperties *props; + + props = user_properties_get (user->bus, user->object_path); + if (props != NULL) { + if (user->props != NULL) + user_properties_free (user->props); + user->props = props; + return TRUE; + } + else { + return FALSE; + } +} + +static void +user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UmUser *user) +{ + if (strcmp (signal_name, "Changed") == 0) { + if (update_info (user)) { + if (user->display_name != NULL) { + um_user_show_full_display_name (user); + } + g_signal_emit (user, signals[CHANGED], 0); + } + } +} + +UmUser * +um_user_new_from_object_path (const gchar *object_path) +{ + UmUser *user; + GError *error = NULL; + + user = (UmUser *)g_object_new (UM_TYPE_USER, NULL); + user->object_path = g_strdup (object_path); + + user->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (user->bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", error->message); + g_error_free (error); + goto error; + } + + user->proxy = g_dbus_proxy_new_sync (user->bus, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.Accounts", + user->object_path, + "org.freedesktop.Accounts.User", + NULL, + &error); + if (user->proxy == NULL) { + g_warning ("Couldn't get user proxy: %s", error->message); + g_error_free (error); + goto error; + } + g_dbus_proxy_set_default_timeout (user->proxy, INT_MAX); + g_signal_connect (user->proxy, "g-signal", G_CALLBACK (user_signal_cb), user); + + if (!update_info (user)) + goto error; + + return user; + + error: + g_object_unref (user); + return NULL; +} + +void +um_user_set_email (UmUser *user, + const gchar *email) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetEmail", g_variant_new ("(s)", email), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetEmail call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_language (UmUser *user, + const gchar *language) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetLanguage", g_variant_new ("(s)", language), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetLanguage call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_location (UmUser *user, + const gchar *location) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetLocation", g_variant_new ("(s)", location), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetLocation call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_user_name (UmUser *user, + const gchar *user_name) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetUserName", g_variant_new ("(s)", user_name), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetUserName call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_real_name (UmUser *user, + const gchar *real_name) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetRealName", g_variant_new ("(s)", real_name), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetRealName call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_icon_file (UmUser *user, + const gchar *icon_file) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetIconFile", g_variant_new ("(s)", icon_file), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetIconFile call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_set_icon_data (UmUser *user, + GdkPixbuf *pixbuf) +{ + gchar *path; + gint fd; + GOutputStream *stream; + GError *error; + + path = g_build_filename (g_get_tmp_dir (), "usericonXXXXXX", NULL); + fd = g_mkstemp (path); + + if (fd == -1) { + g_warning ("failed to create temporary file for image data"); + g_free (path); + return; + } + + stream = g_unix_output_stream_new (fd, TRUE); + + error = NULL; + if (!gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error, NULL)) { + g_warning ("failed to save image: %s", error->message); + g_error_free (error); + g_object_unref (stream); + return; + } + + g_object_unref (stream); + + um_user_set_icon_file (user, path); + + /* if we ever make the dbus call async, the g_remove call needs + * to wait for its completion + */ + g_remove (path); + + g_free (path); +} + +void +um_user_set_account_type (UmUser *user, + gint account_type) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetAccountType", g_variant_new ("(i)", account_type), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetAccountType call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +static gchar +salt_char (GRand *rand) +{ + gchar salt[] = "ABCDEFGHIJKLMNOPQRSTUVXYZ" + "abcdefghijklmnopqrstuvxyz" + "./0123456789"; + + return salt[g_rand_int_range (rand, 0, G_N_ELEMENTS (salt))]; +} + +static gchar * +make_crypted (const gchar *plain) +{ + GString *salt; + gchar *result; + GRand *rand; + gint i; + + rand = g_rand_new (); + salt = g_string_sized_new (21); + + /* SHA 256 */ + g_string_append (salt, "$6$"); + for (i = 0; i < 16; i++) { + g_string_append_c (salt, salt_char (rand)); + } + g_string_append_c (salt, '$'); + + result = g_strdup (crypt (plain, salt->str)); + + g_string_free (salt, TRUE); + g_rand_free (rand); + + return result; +} + +void +um_user_set_password (UmUser *user, + gint password_mode, + const gchar *password, + const gchar *hint) +{ + GError *error = NULL; + gchar *crypted; + + if (password_mode == 0) { + GVariant *result; + + crypted = make_crypted (password); + result = g_dbus_proxy_call_sync (user->proxy, "SetPassword", g_variant_new ("(ss)", crypted, hint), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetPassword call failed: %s", error->message); + g_error_free (error); + } + else + g_variant_unref (result); + memset (crypted, 0, strlen (crypted)); + g_free (crypted); + } + else if (password_mode == 3 || password_mode == 4) { + GVariant *result; + + /* FIXME: this is a slightly odd side-effect: + * you disable the account, and autologin flips + * we should remove that once gdm knows to + * ignore autologin for disabled accounts + */ + if (password_mode == 3 && + um_user_get_automatic_login (user)) { + um_user_set_automatic_login (user, FALSE); + } + result = g_dbus_proxy_call_sync (user->proxy, "SetLocked", g_variant_new ("(b)", password_mode == 3), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetLocked call failed: %s", error->message); + g_error_free (error); + } + else + g_variant_unref (result); + } + else { + GVariant *result; + + result = g_dbus_proxy_call_sync (user->proxy, "SetPasswordMode", g_variant_new ("(i)", password_mode), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetPasswordMode call failed: %s", error->message); + g_error_free (error); + } + else + g_variant_unref (result); + } +} + +#ifdef HAVE_SYSTEMD + +#include + +gboolean +um_user_is_logged_in (UmUser *user) +{ + int n_sessions; + + n_sessions = sd_uid_get_sessions (um_user_get_uid (user), 0, NULL) > 0; + + return n_sessions > 0; +} + +#else + +gboolean +um_user_is_logged_in (UmUser *user) +{ + GVariant *result; + GVariantIter *iter; + gint n_sessions; + GError *error = NULL; + + result = g_dbus_connection_call_sync (user->bus, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "GetSessionsForUnixUser", + g_variant_new ("(u)", um_user_get_uid (user)), + G_VARIANT_TYPE ("(ao)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!result) { + g_warning ("GetSessionsForUnixUser failed: %s", error->message); + g_error_free (error); + return FALSE; + } + + g_variant_get (result, "(ao)", &iter); + n_sessions = g_variant_iter_n_children (iter); + g_variant_iter_free (iter); + g_variant_unref (result); + + return n_sessions > 0; +} + +#endif + +void +um_user_set_automatic_login (UmUser *user, + gboolean enabled) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_sync (user->proxy, "SetAutomaticLogin", g_variant_new ("(b)", enabled), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (!result) { + g_warning ("SetAutomaticLogin call failed: %s", error->message); + g_error_free (error); + return; + } + g_variant_unref (result); +} + +void +um_user_show_full_display_name (UmUser *user) +{ + char *uniq_name; + + g_return_if_fail (UM_IS_USER (user)); + + if (user->props->real_name != NULL) { + uniq_name = g_strdup_printf ("%s (%s)", + user->props->real_name, + user->props->user_name); + } else { + uniq_name = NULL; + } + + if (uniq_name && g_strcmp0 (uniq_name, user->display_name) != 0) { + g_free (user->display_name); + user->display_name = uniq_name; + } + else { + g_free (uniq_name); + } +} + +void +um_user_show_short_display_name (UmUser *user) +{ + g_return_if_fail (UM_IS_USER (user)); + + if (user->display_name) { + g_free (user->display_name); + user->display_name = NULL; + } +} + diff -Nru gnome-control-center-3.6.3/.pc/applied-patches gnome-control-center-3.6.3/.pc/applied-patches --- gnome-control-center-3.6.3/.pc/applied-patches 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/applied-patches 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,60 @@ +git_keyboard_grp_xkb_option.patch +0001-online-accounts-use-the-async-function-to-get-all-th.patch +0001-rfkill-glib-Don-t-use-g_assert_not_reached-in-type_t.patch +05_run_update_manager.patch +06_handle_passwd_with_ldap.patch +11_power-configure_lid_action.patch +12_add_never_turn_screen_off.patch +51_unity_options_in_display_panel.patch +52_region_language.patch +53_use_ubuntu_help.patch +54_enable_alt_tap_in_shortcut.patch +55_user_accounts_hide_controls.patch +56_use_ubuntu_info_branding.patch +58_hide_gdm_notifications.patch +58_ubuntu_icon_views_redesign.patch +59_install_gcm_components_on_demand.patch +60_ubuntu_nav_bar.patch +61_workaround_online_account.patch +64_restore_terminal_keyboard_shortcut.patch +90_force_fallback.patch +91_unity_no_printing_panel.patch +92_ubuntu_system_proxy.patch +97_unity_power_ui.patch +98_default_sound_theme.patch +revert_git_drop_library.patch +99_add_lock-on-suspend.patch +dont_download_local_image.patch +classic_use_sound_indicator.patch +accounts_fix_unsetting_icon.patch +git_set_a11y_wm_theme.patch +git-sound-fix-port-handling.patch +unity_background_is_appareance.patch +git-add-21_9_display.patch +git_no_glxinfo.patch +git-fix-background-panel-crash.patch +git_move_rr_labeler.patch +git_new_goa_build.patch +git-rename-bluetooth-panel.patch +zz_add_fallback_panels_dir.patch +rename_screenshot_media_keys.patch +git_show_per_window_input_settings.patch +git_power_gsd_proxies.patch +ubuntu_update_lock_and_power_settings.patch +git_region_update_input_switch.patch +git_keyboard_update_input_switch.patch +git_shell_use_view_style_class.patch +git-background-remove-unused-widget.patch +git-background-lock-screen.patch +git_rename_natural_scrolling.patch +git_hide_unavailable_layout_settings_btn.patch +git_restore_mouse_speed.patch +git_drop_ibus_engine_whitelist.patch +git_add_printer_crash.patch +ubuntu_update_translations_template.patch +unity_no_zoom_controls.patch +more-power-suspend-options.patch +sanitize_ssid_convert_utf8.patch +git_iconview_columns.patch +gcc_not_in_unity.patch +ubuntu-gnome-version.patch diff -Nru gnome-control-center-3.6.3/.pc/classic_use_sound_indicator.patch/panels/sound/data/gnome-sound-applet.desktop.in gnome-control-center-3.6.3/.pc/classic_use_sound_indicator.patch/panels/sound/data/gnome-sound-applet.desktop.in --- gnome-control-center-3.6.3/.pc/classic_use_sound_indicator.patch/panels/sound/data/gnome-sound-applet.desktop.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/classic_use_sound_indicator.patch/panels/sound/data/gnome-sound-applet.desktop.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Volume Control +_Comment=Show desktop volume control +Icon=multimedia-volume-control +Exec=gnome-sound-applet +Terminal=false +Type=Application +Categories= +NoDisplay=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=sound +# See http://bugzilla.gnome.org/show_bug.cgi?id=568320 +#X-GNOME-Autostart-Phase=Panel +X-GNOME-Autostart-Notify=true +AutostartCondition=GNOME3 if-session gnome-fallback +OnlyShowIn=GNOME;Unity; diff -Nru gnome-control-center-3.6.3/.pc/dont_download_local_image.patch/panels/background/bg-pictures-source.c gnome-control-center-3.6.3/.pc/dont_download_local_image.patch/panels/background/bg-pictures-source.c --- gnome-control-center-3.6.3/.pc/dont_download_local_image.patch/panels/background/bg-pictures-source.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/dont_download_local_image.patch/panels/background/bg-pictures-source.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,585 @@ +/* bg-pictures-source.c */ +/* + * Copyright (C) 2010 Intel, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Thomas Wood + * + */ + +#include "bg-pictures-source.h" + +#include "cc-background-item.h" + +#include +#include +#include +#include + +G_DEFINE_TYPE (BgPicturesSource, bg_pictures_source, BG_TYPE_SOURCE) + +#define PICTURES_SOURCE_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), BG_TYPE_PICTURES_SOURCE, BgPicturesSourcePrivate)) + +#define ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_NAME "," \ + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE + +struct _BgPicturesSourcePrivate +{ + GCancellable *cancellable; + + GnomeDesktopThumbnailFactory *thumb_factory; + + GHashTable *known_items; +}; + +const char * const content_types[] = { + "image/png", + "image/jpeg", + "image/bmp", + "image/svg+xml", + NULL +}; + +static char *bg_pictures_source_get_unique_filename (const char *uri); + +static void +bg_pictures_source_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +bg_pictures_source_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +bg_pictures_source_dispose (GObject *object) +{ + BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (object)->priv; + + if (priv->cancellable) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + if (priv->thumb_factory) + { + g_object_unref (priv->thumb_factory); + priv->thumb_factory = NULL; + } + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->dispose (object); +} + +static void +bg_pictures_source_finalize (GObject *object) +{ + BgPicturesSource *bg_source = BG_PICTURES_SOURCE (object); + + if (bg_source->priv->thumb_factory) + { + g_object_unref (bg_source->priv->thumb_factory); + bg_source->priv->thumb_factory = NULL; + } + + if (bg_source->priv->known_items) + { + g_hash_table_destroy (bg_source->priv->known_items); + bg_source->priv->known_items = NULL; + } + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->finalize (object); +} + +static void +bg_pictures_source_class_init (BgPicturesSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (BgPicturesSourcePrivate)); + + object_class->get_property = bg_pictures_source_get_property; + object_class->set_property = bg_pictures_source_set_property; + object_class->dispose = bg_pictures_source_dispose; + object_class->finalize = bg_pictures_source_finalize; +} + +static int +sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + BgPicturesSource *bg_source) +{ + CcBackgroundItem *item_a; + CcBackgroundItem *item_b; + const char *name_a; + const char *name_b; + int retval; + + gtk_tree_model_get (model, a, + 1, &item_a, + -1); + gtk_tree_model_get (model, b, + 1, &item_b, + -1); + + name_a = cc_background_item_get_name (item_a); + name_b = cc_background_item_get_name (item_b); + + retval = g_utf8_collate (name_a, name_b); + + g_object_unref (item_a); + g_object_unref (item_b); + + return retval; +} + +static void +picture_scaled (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + GError *error = NULL; + GdkPixbuf *pixbuf; + const char *source_url; + const char *software; + GtkTreeIter iter; + GtkListStore *store; + + pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error); + if (pixbuf == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to load image: %s", error->message); + + g_error_free (error); + return; + } + + /* since we were not cancelled, we can now cast user_data + * back to BgPicturesSource. + */ + bg_source = BG_PICTURES_SOURCE (user_data); + store = bg_source_get_liststore (BG_SOURCE (bg_source)); + item = g_object_get_data (source_object, "item"); + + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), + 1, + (GtkTreeIterCompareFunc)sort_func, + bg_source, + NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + 1, + GTK_SORT_ASCENDING); + + /* Ignore screenshots */ + software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software"); + if (software != NULL && + g_str_equal (software, "gnome-screenshot")) + { + g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot", + cc_background_item_get_uri (item)); + g_object_unref (pixbuf); + g_object_unref (item); + return; + } + + cc_background_item_load (item, NULL); + + /* insert the item into the liststore */ + gtk_list_store_insert_with_values (store, &iter, 0, + 0, pixbuf, + 1, item, + -1); + source_url = cc_background_item_get_source_url (item); + if (source_url != NULL) + { + g_hash_table_insert (bg_source->priv->known_items, + bg_pictures_source_get_unique_filename (source_url), GINT_TO_POINTER (TRUE)); + } + else + { + char *cache_path; + GFile *file, *parent, *dir; + + cache_path = bg_pictures_source_get_cache_path (); + dir = g_file_new_for_path (cache_path); + g_free (cache_path); + + file = g_file_new_for_uri (cc_background_item_get_uri (item)); + parent = g_file_get_parent (file); + + if (g_file_equal (parent, dir)) + { + char *basename; + basename = g_file_get_basename (file); + g_hash_table_insert (bg_source->priv->known_items, + basename, GINT_TO_POINTER (TRUE)); + } + g_object_unref (file); + g_object_unref (parent); + } + + g_object_unref (pixbuf); +} + +static void +picture_opened_for_read (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + GFileInputStream *stream; + GError *error = NULL; + + item = g_object_get_data (source_object, "item"); + stream = g_file_read_finish (G_FILE (source_object), res, &error); + if (stream == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + char *filename = g_file_get_path (G_FILE (source_object)); + g_warning ("Failed to load picture '%s': %s", filename, error->message); + g_free (filename); + } + + g_error_free (error); + g_object_unref (item); + return; + } + + /* since we were not cancelled, we can now cast user_data + * back to BgPicturesSource. + */ + bg_source = BG_PICTURES_SOURCE (user_data); + + g_object_set_data (G_OBJECT (stream), "item", item); + gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (stream), + THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, + TRUE, + bg_source->priv->cancellable, + picture_scaled, bg_source); + g_object_unref (stream); +} + +static gboolean +in_content_types (const char *content_type) +{ + guint i; + for (i = 0; content_types[i]; i++) + if (g_str_equal (content_types[i], content_type)) + return TRUE; + return FALSE; +} + +static gboolean +add_single_file (BgPicturesSource *bg_source, + GFile *file, + GFileInfo *info, + const char *source_uri) +{ + const gchar *content_type; + CcBackgroundItem *item; + char *uri; + + /* find png and jpeg files */ + content_type = g_file_info_get_content_type (info); + + if (!content_type) + return FALSE; + if (!in_content_types (content_type)) + return FALSE; + + /* create a new CcBackgroundItem */ + uri = g_file_get_uri (file); + item = cc_background_item_new (uri); + g_free (uri); + g_object_set (G_OBJECT (item), + "flags", CC_BACKGROUND_ITEM_HAS_URI | CC_BACKGROUND_ITEM_HAS_SHADING, + "shading", G_DESKTOP_BACKGROUND_SHADING_SOLID, + "placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM, + NULL); + if (source_uri != NULL) + g_object_set (G_OBJECT (item), "source-url", source_uri, NULL); + + g_object_set_data (G_OBJECT (file), "item", item); + g_file_read_async (file, G_PRIORITY_DEFAULT, + bg_source->priv->cancellable, + picture_opened_for_read, bg_source); + g_object_unref (file); + return TRUE; +} + +gboolean +bg_pictures_source_add (BgPicturesSource *bg_source, + const char *uri) +{ + GFile *file; + GFileInfo *info; + gboolean retval; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, ATTRIBUTES, G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (info == NULL) + return FALSE; + + retval = add_single_file (bg_source, file, info, uri); + + return retval; +} + +gboolean +bg_pictures_source_remove (BgPicturesSource *bg_source, + CcBackgroundItem *item) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean cont; + const char *uri; + gboolean retval; + + retval = FALSE; + model = GTK_TREE_MODEL (bg_source_get_liststore (BG_SOURCE (bg_source))); + uri = cc_background_item_get_uri (item); + + cont = gtk_tree_model_get_iter_first (model, &iter); + while (cont) + { + CcBackgroundItem *tmp_item; + const char *tmp_uri; + + gtk_tree_model_get (model, &iter, 1, &tmp_item, -1); + tmp_uri = cc_background_item_get_uri (tmp_item); + if (g_str_equal (tmp_uri, uri)) + { + GFile *file; + char *uuid; + + file = g_file_new_for_uri (uri); + uuid = g_file_get_basename (file); + g_hash_table_insert (bg_source->priv->known_items, + uuid, NULL); + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + retval = TRUE; + g_file_trash (file, NULL, NULL); + g_object_unref (file); + break; + } + g_object_unref (tmp_item); + cont = gtk_tree_model_iter_next (model, &iter); + } + return retval; +} + +static void +file_info_async_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source = BG_PICTURES_SOURCE (user_data); + GList *files, *l; + GError *err = NULL; + GFile *parent; + files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source), + res, + &err); + + if (err) + { + g_warning ("Could not get pictures file information: %s", err->message); + g_error_free (err); + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); + return; + } + + parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); + + /* iterate over the available files */ + for (l = files; l; l = g_list_next (l)) + { + GFileInfo *info = l->data; + GFile *file; + + file = g_file_get_child (parent, g_file_info_get_name (info)); + + add_single_file (bg_source, file, info, NULL); + } + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); +} + +static void +dir_enum_async_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (user_data)->priv; + GFileEnumerator *enumerator; + GError *err = NULL; + + enumerator = g_file_enumerate_children_finish (G_FILE (source), res, &err); + + if (err) + { + if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) == FALSE) + g_warning ("Could not fill pictures source: %s", err->message); + g_error_free (err); + return; + } + + /* get the files */ + g_file_enumerator_next_files_async (enumerator, + G_MAXINT, + G_PRIORITY_LOW, + priv->cancellable, + file_info_async_ready, + user_data); +} + +char * +bg_pictures_source_get_cache_path (void) +{ + return g_build_filename (g_get_user_cache_dir (), + "gnome-control-center", + "backgrounds", + NULL); +} + +static char * +bg_pictures_source_get_unique_filename (const char *uri) +{ + GChecksum *csum; + char *ret; + + csum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (csum, (guchar *) uri, -1); + ret = g_strdup (g_checksum_get_string (csum)); + g_checksum_free (csum); + + return ret; +} + +char * +bg_pictures_source_get_unique_path (const char *uri) +{ + GFile *parent, *file; + char *cache_path; + char *filename; + char *ret; + + cache_path = bg_pictures_source_get_cache_path (); + parent = g_file_new_for_path (cache_path); + g_free (cache_path); + + filename = bg_pictures_source_get_unique_filename (uri); + file = g_file_get_child (parent, filename); + g_free (filename); + ret = g_file_get_path (file); + g_object_unref (file); + + return ret; +} + +gboolean +bg_pictures_source_is_known (BgPicturesSource *bg_source, + const char *uri) +{ + gboolean retval; + char *uuid; + + uuid = bg_pictures_source_get_unique_filename (uri); + retval = (GPOINTER_TO_INT (g_hash_table_lookup (bg_source->priv->known_items, uuid))); + g_free (uuid); + + return retval; +} + +static void +bg_pictures_source_init (BgPicturesSource *self) +{ + const gchar *pictures_path; + BgPicturesSourcePrivate *priv; + GFile *dir; + char *cache_path; + + priv = self->priv = PICTURES_SOURCE_PRIVATE (self); + + priv->cancellable = g_cancellable_new (); + priv->known_items = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); + + pictures_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); + dir = g_file_new_for_path (pictures_path); + g_file_enumerate_children_async (dir, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, priv->cancellable, + dir_enum_async_ready, self); + g_object_unref (dir); + + cache_path = bg_pictures_source_get_cache_path (); + dir = g_file_new_for_path (cache_path); + g_file_enumerate_children_async (dir, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, priv->cancellable, + dir_enum_async_ready, self); + g_object_unref (dir); + + priv->thumb_factory = + gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); +} + +BgPicturesSource * +bg_pictures_source_new (void) +{ + return g_object_new (BG_TYPE_PICTURES_SOURCE, NULL); +} + +const char * const * +bg_pictures_get_support_content_types (void) +{ + return content_types; +} diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/bluetooth/gnome-bluetooth-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,15 @@ +[Desktop Entry] +_Name=Bluetooth +_Comment=Configure Bluetooth settings +Icon=bluetooth +Exec=gnome-control-center bluetooth +Terminal=false +Type=Application +Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +StartupNotify=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-bluetooth +X-GNOME-Bugzilla-Component=properties +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=bluetooth diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/color/gnome-color-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/color/gnome-color-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/color/gnome-color-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/color/gnome-color-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Color +_Comment=Color management settings +Exec=gnome-control-center color +Icon=preferences-color +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=color +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=color +# Translators: those are keywords for the color control-center panel +_Keywords=Color;ICC;Profile;Calibrate;Printer;Display; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/display/gnome-display-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/display/gnome-display-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/display/gnome-display-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/display/gnome-display-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Displays +_Comment=Change resolution and position of monitors and projectors +Exec=gnome-control-center display +Icon=preferences-desktop-display +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=Screen resolution +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=display +# Translators: those are keywords for the display control-center panel +_Keywords=Panel;Projector;xrandr;Screen;Resolution;Refresh; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/info/gnome-info-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/info/gnome-info-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/info/gnome-info-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/info/gnome-info-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,19 @@ +[Desktop Entry] +_Name=Details +_Comment=System Information +Exec=gnome-control-center info +Icon=applications-system +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=info +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=info +# Translators: those are keywords for the System Information panel +# "Preferred Applications" is the old name for the preference, so make +# sure that you use the same "translation" for those keywords +_Keywords=device;system;information;memory;processor;version;default;application;fallback;preferred;cd;dvd;usb;audio;video;disc;removable;media;autorun; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/keyboard/gnome-keyboard-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/keyboard/gnome-keyboard-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/keyboard/gnome-keyboard-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/keyboard/gnome-keyboard-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Keyboard +_Comment=Change keyboard settings +Exec=gnome-control-center keyboard +Icon=input-keyboard +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=keyboard +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=keyboard +# Translators: those are keywords for the keyboard control-center panel +_Keywords=Shortcut;Repeat;Blink; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/mouse/gnome-mouse-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/mouse/gnome-mouse-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/mouse/gnome-mouse-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/mouse/gnome-mouse-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Mouse & Touchpad +_Comment=Set your mouse and touchpad preferences +Exec=gnome-control-center mouse +Icon=input-mouse +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=mouse +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=mouse +# Translators: those are keywords for the mouse and touchpad control-center panel +_Keywords=Trackpad;Pointer;Click;Tap;Double;Button;Trackball; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/network/gnome-network-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/network/gnome-network-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/network/gnome-network-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/network/gnome-network-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Network +_Comment=Network settings +Exec=gnome-control-center network +Icon=network-workgroup +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=network +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=network +# Translators: those are keywords for the network control-center panel +_Keywords=Network;Wireless;IP;LAN;Proxy; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/power/gnome-power-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/power/gnome-power-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/power/gnome-power-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/power/gnome-power-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Power +_Comment=Power management settings +Exec=gnome-control-center power +Icon=gnome-power-manager +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;HardwareSettings +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=power +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=power +# Translators: those are keywords for the power control-center panel +_Keywords=Power;Sleep;Suspend;Hibernate;Battery; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/region/gnome-region-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/region/gnome-region-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/region/gnome-region-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/region/gnome-region-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Region & Language +_Comment=Change your region and language settings +Exec=gnome-control-center region +Icon=preferences-desktop-locale +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=region +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=region +# Translators: those are keywords for the region control-center panel +_Keywords=Language;Layout;Keyboard; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/screen/gnome-screen-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/screen/gnome-screen-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/screen/gnome-screen-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/screen/gnome-screen-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Brightness & Lock +_Comment=Screen brightness and lock settings +Exec=gnome-control-center screen +Icon=system-lock-screen +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=screen +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=screen +# Translators: those are keywords for the brightness and lock control-center panel +_Keywords=Brightness;Lock;Dim;Blank;Monitor; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/sound/data/gnome-sound-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/sound/data/gnome-sound-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/sound/data/gnome-sound-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/sound/data/gnome-sound-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Sound +_Comment=Change sound volume and sound events +Exec=gnome-control-center sound +Icon=multimedia-volume-control +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=sound +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=sound +# Translators: those are keywords for the sound control-center panel +_Keywords=Card;Microphone;Volume;Fade;Balance;Bluetooth;Headset;Audio; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/universal-access/gnome-universal-access-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/universal-access/gnome-universal-access-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/universal-access/gnome-universal-access-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/universal-access/gnome-universal-access-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Universal Access +_Comment=Universal Access Preferences +Exec=gnome-control-center universal-access +Icon=preferences-desktop-accessibility +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;X-GNOME-SystemSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=Universal Access +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=universal-access +# Translators: those are keywords for the universal access control-center panel +_Keywords=Keyboard;Mouse;a11y;Accessibility;Contrast;Zoom;Screen Reader;text;font;size;AccessX;Sticky Keys;Slow Keys;Bounce Keys;Mouse Keys; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=User Accounts +_Comment=Add or remove users +Exec=gnome-control-center user-accounts +Icon=system-users +Terminal=false +Type=Application +StartupNotify=true +Categories=System;Settings;X-GNOME-Settings-Panel;X-GNOME-SystemSettings +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=user-accounts +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=user-accounts +# Translators: those are keywords for the user accounts control-center panel +_Keywords=Login;Name;Fingerprint;Avatar;Logo;Face;Password; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/wacom/gnome-wacom-panel.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/wacom/gnome-wacom-panel.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/wacom/gnome-wacom-panel.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/panels/wacom/gnome-wacom-panel.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,17 @@ +[Desktop Entry] +_Name=Wacom Tablet +_Comment=Set your Wacom tablet preferences +Exec=gnome-control-center wacom +Icon=input-tablet +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=wacom +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=wacom +# Translators: those are keywords for the wacom tablet control-center panel +_Keywords=Tablet;Wacom;Stylus;Eraser;Mouse; diff -Nru gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/shell/gnome-control-center.desktop.in.in gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/shell/gnome-control-center.desktop.in.in --- gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/shell/gnome-control-center.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/gcc_not_in_unity.patch/shell/gnome-control-center.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,14 @@ +[Desktop Entry] +_Name=System Settings +Icon=preferences-system +Exec=gnome-control-center --overview +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;System; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=shell +X-GNOME-Bugzilla-Version=@VERSION@ +_Keywords=Preferences;Settings; diff -Nru gnome-control-center-3.6.3/.pc/git-add-21_9_display.patch/panels/display/cc-display-panel.c gnome-control-center-3.6.3/.pc/git-add-21_9_display.patch/panels/display/cc-display-panel.c --- gnome-control-center-3.6.3/.pc/git-add-21_9_display.patch/panels/display/cc-display-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-add-21_9_display.patch/panels/display/cc-display-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,2986 @@ +/* + * Copyright (C) 2007, 2008 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Soren Sandmann + * + */ + +#include +#include +#include +#include + +#include "cc-display-panel.h" + +#include +#include "scrollarea.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include +#include +#include +#include +#include +#include + +CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) + +#define DISPLAY_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DISPLAY_PANEL, CcDisplayPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +#define TOP_BAR_HEIGHT 10 + +#define CLOCK_SCHEMA "org.gnome.desktop.interface" +#define CLOCK_FORMAT_KEY "clock-format" + +/* The minimum supported size for the panel, see: + * http://live.gnome.org/Design/SystemSettings */ +#define MINIMUM_WIDTH 675 +#define MINIMUM_HEIGHT 530 + +#define UNITY_GSETTINGS_SCHEMA "org.compiz.unityshell" +#define UNITY_GSETTINGS_PATH "/org/compiz/profiles/unity/plugins/unityshell/" +#define UNITY_LAUNCHER_ALL_MONITORS_KEY "num-launchers" +#define UNITY_STICKY_EDGE_KEY "launcher-capture-mouse" +#define UNITY2D_GSETTINGS_MAIN "com.canonical.Unity2d" +#define UNITY2D_GSETTINGS_LAUNCHER "com.canonical.Unity2d.Launcher" + +enum { + TEXT_COL, + WIDTH_COL, + HEIGHT_COL, + RATE_COL, + SORT_COL, + ROTATION_COL, + NUM_COLS +}; + +struct _CcDisplayPanelPrivate +{ + GnomeRRScreen *screen; + GnomeRRConfig *current_configuration; + GnomeRRLabeler *labeler; + GnomeRROutputInfo *current_output; + + GSettings *clock_settings; + GSettings *unity_settings; + GSettings *unity2d_settings_main; + GSettings *unity2d_settings_launcher; + GtkBuilder *builder; + guint focus_id; + + GtkWidget *panel; + GtkWidget *current_monitor_event_box; + GtkWidget *current_monitor_label; + GtkWidget *monitor_switch; + GtkListStore *resolution_store; + GtkWidget *resolution_combo; + GtkWidget *rotation_combo; + GtkWidget *clone_checkbox; + GtkWidget *clone_label; + GtkWidget *show_icon_checkbox; + + /* We store the event timestamp when the Apply button is clicked */ + guint32 apply_button_clicked_timestamp; + + GtkWidget *area; + gboolean ignore_gui_changes; + gboolean dragging_top_bar; + + /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */ + GDBusProxy *proxy; +}; + +typedef struct +{ + int grab_x; + int grab_y; + int output_x; + int output_y; +} GrabInfo; + +static void rebuild_gui (CcDisplayPanel *self); +static void on_clone_changed (GtkWidget *box, gpointer data); +static gboolean output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config); +static void select_current_output_from_dialog_position (CcDisplayPanel *self); +static void monitor_switch_active_cb (GObject *object, GParamSpec *pspec, gpointer data); +static void get_geometry (GnomeRROutputInfo *output, int *w, int *h); +static void apply_configuration_returned_cb (GObject *proxy, GAsyncResult *res, gpointer data); +static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height); +static gboolean output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height); +static char *make_resolution_string (int width, int height); +static GObject *cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties); +static void on_screen_changed (GnomeRRScreen *scr, gpointer data); +static void refresh_unity_launcher_placement (CcDisplayPanel *self); +static gboolean unity_launcher_on_all_monitors (GSettings *settings); + +static void +cc_display_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_dispose (GObject *object) +{ + G_OBJECT_CLASS (cc_display_panel_parent_class)->dispose (object); +} + +static void +cc_display_panel_finalize (GObject *object) +{ + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + + self = CC_DISPLAY_PANEL (object); + + g_signal_handlers_disconnect_by_func (self->priv->screen, on_screen_changed, self); + g_object_unref (self->priv->screen); + g_object_unref (self->priv->builder); + + if (self->priv->clock_settings != NULL) + g_object_unref (self->priv->clock_settings); + + if (self->priv->unity2d_settings_main != NULL) + g_object_unref (self->priv->unity2d_settings_main); + if (self->priv->unity2d_settings_launcher != NULL) + g_object_unref (self->priv->unity2d_settings_launcher); + if (self->priv->unity_settings != NULL) + g_object_unref (self->priv->unity_settings); + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (shell != NULL) + { + toplevel = cc_shell_get_toplevel (shell); + if (toplevel != NULL) + g_signal_handler_disconnect (G_OBJECT (toplevel), + self->priv->focus_id); + } + + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + + G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); +} + +static const char * +cc_display_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; +} + +static void +cc_display_panel_class_init (CcDisplayPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcDisplayPanelPrivate)); + + panel_class->get_help_uri = cc_display_panel_get_help_uri; + + object_class->constructor = cc_display_panel_constructor; + object_class->get_property = cc_display_panel_get_property; + object_class->set_property = cc_display_panel_set_property; + object_class->dispose = cc_display_panel_dispose; + object_class->finalize = cc_display_panel_finalize; +} + +static void +error_message (CcDisplayPanel *self, const char *primary_text, const char *secondary_text) +{ + GtkWidget *toplevel; + GtkWidget *dialog; + + if (self && self->priv->panel) + toplevel = gtk_widget_get_toplevel (self->priv->panel); + else + toplevel = NULL; + + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + + if (secondary_text) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static gboolean +is_unity_session (void) +{ + return (g_strcmp0 (g_getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0); +} + +static gboolean +should_show_resolution (gint output_width, + gint output_height, + gint width, + gint height) +{ + if (width >= MIN (output_width, MINIMUM_WIDTH) && + height >= MIN (output_height, MINIMUM_HEIGHT)) + { + return TRUE; + } + return FALSE; +} + +static void +on_screen_changed (GnomeRRScreen *scr, + gpointer data) +{ + GnomeRRConfig *current; + CcDisplayPanel *self = data; + + current = gnome_rr_config_new_current (self->priv->screen, NULL); + gnome_rr_config_ensure_primary (current); + + if (self->priv->current_configuration) + g_object_unref (self->priv->current_configuration); + + self->priv->current_configuration = current; + self->priv->current_output = NULL; + + if (self->priv->labeler) { + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + } + + self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); + if (gtk_widget_has_focus (self->priv->panel)) + gnome_rr_labeler_show (self->priv->labeler); + + select_current_output_from_dialog_position (self); + + if (is_unity_session ()) + refresh_unity_launcher_placement (self); +} + +static void +on_viewport_changed (FooScrollArea *scroll_area, + GdkRectangle *old_viewport, + GdkRectangle *new_viewport) +{ + foo_scroll_area_set_size (scroll_area, + new_viewport->width, + new_viewport->height); + + foo_scroll_area_invalidate (scroll_area); +} + +static void +layout_set_font (PangoLayout *layout, const char *font) +{ + PangoFontDescription *desc = + pango_font_description_from_string (font); + + if (desc) + { + pango_layout_set_font_description (layout, desc); + + pango_font_description_free (desc); + } +} + +static void +clear_combo (GtkWidget *widget) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + GtkListStore *store = GTK_LIST_STORE (model); + + gtk_list_store_clear (store); +} + +typedef struct +{ + const char *text; + gboolean found; + GtkTreeIter iter; +} ForeachInfo; + +static gboolean +foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + ForeachInfo *info = data; + char *text = NULL; + + gtk_tree_model_get (model, iter, TEXT_COL, &text, -1); + + g_assert (text != NULL); + + if (strcmp (info->text, text) == 0) + { + info->found = TRUE; + info->iter = *iter; + return TRUE; + } + + return FALSE; +} + +static void +add_key (GtkTreeModel *model, + const char *text, + gboolean preferred, + int width, int height, int rate, + GnomeRRRotation rotation) +{ + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + { + GtkTreeIter iter; + g_debug ("adding %s with rate %d Hz", text, rate); + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, -1, + TEXT_COL, text, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + SORT_COL, width * 10000 + height, + ROTATION_COL, rotation, + -1); + return; + } + + /* Look, the preferred output, replace the old one */ + if (preferred) + { + g_debug ("replacing %s with rate %d Hz (preferred mode)", text, rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + + { + int old_rate; + + gtk_tree_model_get (model, &info.iter, + RATE_COL, &old_rate, + -1); + + /* Higher refresh rate */ + if (rate > old_rate) + { + g_debug ("replacing %s with rate %d Hz (old rate: %d)", text, rate, old_rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + } + + g_debug ("not adding %s with rate %d Hz (higher rate already there)", text, rate); +} + +static void +add_mode (CcDisplayPanel *self, + GnomeRRMode *mode, + gint output_width, + gint output_height, + guint preferred_id) +{ + int width, height, rate; + + width = gnome_rr_mode_get_width (mode); + height = gnome_rr_mode_get_height (mode); + rate = gnome_rr_mode_get_freq (mode); + + if (should_show_resolution (output_width, output_height, width, height)) + { + char *text; + gboolean preferred; + + preferred = (gnome_rr_mode_get_id (mode) == preferred_id); + text = make_resolution_string (width, height); + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->resolution_combo)), + text, preferred, width, height, rate, -1); + g_free (text); + } +} + + + +static gboolean +combo_select (GtkWidget *widget, const char *text) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + return FALSE; + + gtk_combo_box_set_active_iter (box, &info.iter); + return TRUE; +} + +static GnomeRRMode ** +get_current_modes (CcDisplayPanel *self) +{ + GnomeRROutput *output; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + return gnome_rr_screen_list_clone_modes (self->priv->screen); + } + else + { + if (!self->priv->current_output) + return NULL; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + + if (!output) + return NULL; + + return gnome_rr_output_list_modes (output); + } +} + +static void +rebuild_rotation_combo (CcDisplayPanel *self) +{ + typedef struct + { + GnomeRRRotation rotation; + const char * name; + } RotationInfo; + static const RotationInfo rotations[] = { + { GNOME_RR_ROTATION_0, NC_("display panel, rotation", "Normal") }, + { GNOME_RR_ROTATION_90, NC_("display panel, rotation", "Counterclockwise") }, + { GNOME_RR_ROTATION_270, NC_("display panel, rotation", "Clockwise") }, + { GNOME_RR_ROTATION_180, NC_("display panel, rotation", "180 Degrees") }, + }; + const char *selection; + GnomeRRRotation current; + int i; + + clear_combo (self->priv->rotation_combo); + + gtk_widget_set_sensitive (self->priv->rotation_combo, + self->priv->current_output && gnome_rr_output_info_is_active (self->priv->current_output)); + + if (!self->priv->current_output) + return; + + current = gnome_rr_output_info_get_rotation (self->priv->current_output); + + selection = NULL; + for (i = 0; i < G_N_ELEMENTS (rotations); ++i) + { + const RotationInfo *info = &(rotations[i]); + + gnome_rr_output_info_set_rotation (self->priv->current_output, info->rotation); + + /* NULL-GError --- FIXME: we should say why this rotation is not available! */ + if (gnome_rr_config_applicable (self->priv->current_configuration, self->priv->screen, NULL)) + { + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->rotation_combo)), g_dpgettext2 (NULL, "display panel, rotation", info->name), FALSE, 0, 0, 0, info->rotation); + + if (info->rotation == current) + selection = g_dpgettext2 (NULL, "display panel, rotation", info->name); + } + } + + gnome_rr_output_info_set_rotation (self->priv->current_output, current); + + if (!(selection && combo_select (self->priv->rotation_combo, selection))) + gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->rotation_combo), 0); +} + +static int +count_active_outputs (CcDisplayPanel *self) +{ + int i, count = 0; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_active (outputs[i])) + count++; + } + + return count; +} + +#if 0 +static int +count_all_outputs (GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) + ; + + return i; +} +#endif + +/* Computes whether "Mirror displays" (clone mode) is supported based on these criteria: + * + * 1. There is an available size for cloning. + * + * 2. There are 2 or more connected outputs that support that size. + */ +static gboolean +mirror_screens_is_supported (CcDisplayPanel *self) +{ + int clone_width, clone_height; + gboolean have_clone_size; + gboolean mirror_is_supported; + + mirror_is_supported = FALSE; + + have_clone_size = get_clone_size (self->priv->screen, &clone_width, &clone_height); + + if (have_clone_size) { + int i; + int num_outputs_with_clone_size; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + num_outputs_with_clone_size = 0; + + for (i = 0; outputs[i] != NULL; i++) + { + /* We count the connected outputs that support the clone size. It + * doesn't matter if those outputs aren't actually On currently; we + * will turn them on in on_clone_changed(). + */ + if (gnome_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (self, outputs[i], clone_width, clone_height)) + num_outputs_with_clone_size++; + } + + if (num_outputs_with_clone_size >= 2) + mirror_is_supported = TRUE; + } + + return mirror_is_supported; +} + +static void +rebuild_mirror_screens (CcDisplayPanel *self) +{ + gboolean mirror_is_active; + gboolean mirror_is_supported; + + g_signal_handlers_block_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); + + mirror_is_active = self->priv->current_configuration && gnome_rr_config_get_clone (self->priv->current_configuration); + + /* If mirror_is_active, then it *must* be possible to turn mirroring off */ + mirror_is_supported = mirror_is_active || mirror_screens_is_supported (self); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox), mirror_is_active); + gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); + gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); + + /* set inactive the launcher placement choice */ + gtk_widget_set_sensitive (WID ("launcher_placement_combo"), !mirror_is_active); + gtk_widget_set_sensitive (WID ("stickyedge_switch"), !mirror_is_active); + + g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); +} + +static char * +mirror_monitor_name (void) +{ + /* Keep this string in sync with gnome-desktop/libgnome-desktop/gnome-rr-labeler.c */ + + /* Translators: this is the feature where what you see on your laptop's + * screen is the same as your external projector. Here, "Mirrored" is being + * used as an adjective. For example, the Spanish translation could be + * "Pantallas en Espejo". + */ + return g_strdup (_("Mirrored Displays")); +} + +static void +rebuild_current_monitor_label (CcDisplayPanel *self) +{ + char *str, *tmp; + GdkRGBA color; + gboolean use_color; + + if (self->priv->current_output) + { + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + tmp = mirror_monitor_name (); + else + tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); + + str = g_strdup_printf ("%s", tmp); + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); + use_color = TRUE; + g_free (tmp); + } + else + { + str = g_strdup_printf ("%s", _("Monitor")); + use_color = FALSE; + } + + gtk_label_set_markup (GTK_LABEL (self->priv->current_monitor_label), str); + g_free (str); + + if (use_color) + { + GdkRGBA black = { 0, 0, 0, 1.0 }; + + gtk_widget_override_background_color (self->priv->current_monitor_event_box, + gtk_widget_get_state_flags (self->priv->current_monitor_event_box), + &color); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + &black); + } + else + { + /* Remove any modifications we did on the label's color */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + NULL); + } + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (self->priv->current_monitor_event_box), use_color); +} + +static void +rebuild_on_off_radios (CcDisplayPanel *self) +{ + gboolean sensitive; + gboolean on_active; + + g_signal_handlers_block_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); + + sensitive = FALSE; + on_active = FALSE; + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && self->priv->current_output) + { + if (count_active_outputs (self) > 1 || !gnome_rr_output_info_is_active (self->priv->current_output)) + sensitive = TRUE; + else + sensitive = FALSE; + + on_active = gnome_rr_output_info_is_active (self->priv->current_output); + } + + gtk_widget_set_sensitive (self->priv->monitor_switch, sensitive); + + gtk_switch_set_active (GTK_SWITCH (self->priv->monitor_switch), on_active); + + g_signal_handlers_unblock_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); +} + +static char * +make_resolution_string (int width, int height) +{ + int ratio; + const char *aspect = NULL; + + if (width && height) { + if (width > height) + ratio = width * 10 / height; + else + ratio = height * 10 / width; + + switch (ratio) { + case 13: + aspect = "4:3"; + break; + case 16: + aspect = "16:10"; + break; + case 17: + aspect = "16:9"; + break; + case 12: + aspect = "5:4"; + break; + /* This catches 1.5625 as well (1600x1024) when maybe it shouldn't. */ + case 15: + aspect = "3:2"; + break; + case 18: + aspect = "9:5"; + break; + case 10: + aspect = "1:1"; + break; + } + } + + if (aspect != NULL) + return g_strdup_printf (_("%d x %d (%s)"), width, height, aspect); + else + return g_strdup_printf (_("%d x %d"), width, height); +} + +static void +find_best_mode (GnomeRRMode **modes, int *out_width, int *out_height) +{ + int i; + + *out_width = 0; + *out_height = 0; + + for (i = 0; modes[i] != NULL; i++) + { + int w, h; + + w = gnome_rr_mode_get_width (modes[i]); + h = gnome_rr_mode_get_height (modes[i]); + + if (w * h > *out_width * *out_height) + { + *out_width = w; + *out_height = h; + } + } +} + +static void +rebuild_resolution_combo (CcDisplayPanel *self) +{ + int i; + GnomeRRMode **modes; + GnomeRRMode *mode; + char *current; + int output_width, output_height; + guint32 preferred_id; + GnomeRROutput *output; + + clear_combo (self->priv->resolution_combo); + + if (!(modes = get_current_modes (self)) + || !self->priv->current_output + || !gnome_rr_output_info_is_active (self->priv->current_output)) + { + gtk_widget_set_sensitive (self->priv->resolution_combo, FALSE); + return; + } + + g_assert (self->priv->current_output != NULL); + + gnome_rr_output_info_get_geometry (self->priv->current_output, NULL, NULL, &output_width, &output_height); + g_assert (output_width != 0 && output_height != 0); + + gtk_widget_set_sensitive (self->priv->resolution_combo, TRUE); + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + mode = gnome_rr_output_get_preferred_mode (output); + preferred_id = gnome_rr_mode_get_id (mode); + + for (i = 0; modes[i] != NULL; ++i) + add_mode (self, modes[i], output_width, output_height, preferred_id); + + /* And force the preferred mode in the drop-down (when not in clone mode) + * https://bugzilla.gnome.org/show_bug.cgi?id=680969 */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration)) + add_mode (self, mode, output_width, output_height, preferred_id); + + current = make_resolution_string (output_width, output_height); + + if (!combo_select (self->priv->resolution_combo, current)) + { + int best_w, best_h; + char *str; + + find_best_mode (modes, &best_w, &best_h); + str = make_resolution_string (best_w, best_h); + combo_select (self->priv->resolution_combo, str); + g_free (str); + } + + g_free (current); +} + +static void +rebuild_gui (CcDisplayPanel *self) +{ + /* We would break spectacularly if we recursed, so + * just assert if that happens + */ + g_assert (self->priv->ignore_gui_changes == FALSE); + + self->priv->ignore_gui_changes = TRUE; + + rebuild_mirror_screens (self); + rebuild_current_monitor_label (self); + rebuild_on_off_radios (self); + rebuild_resolution_combo (self); + rebuild_rotation_combo (self); + refresh_unity_launcher_placement (self); + + self->priv->ignore_gui_changes = FALSE; +} + +static gboolean +get_mode (GtkWidget *widget, int *width, int *height, int *rate, GnomeRRRotation *rot) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkComboBox *box = GTK_COMBO_BOX (widget); + int dummy; + + if (!gtk_combo_box_get_active_iter (box, &iter)) + return FALSE; + + if (!width) + width = &dummy; + + if (!height) + height = &dummy; + + if (!rate) + rate = &dummy; + + if (!rot) + rot = (GnomeRRRotation *)&dummy; + + model = gtk_combo_box_get_model (box); + gtk_tree_model_get (model, &iter, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + ROTATION_COL, rot, + -1); + + return TRUE; + +} + +static void +on_rotation_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + GnomeRRRotation rotation; + + if (!self->priv->current_output) + return; + + if (get_mode (self->priv->rotation_combo, NULL, NULL, NULL, &rotation)) + gnome_rr_output_info_set_rotation (self->priv->current_output, rotation); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +select_resolution_for_current_output (CcDisplayPanel *self) +{ + GnomeRRMode **modes; + int width, height; + int x,y; + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, NULL, NULL); + + width = gnome_rr_output_info_get_preferred_width (self->priv->current_output); + height = gnome_rr_output_info_get_preferred_height (self->priv->current_output); + + if (width != 0 && height != 0) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + return; + } + + modes = get_current_modes (self); + if (!modes) + return; + + find_best_mode (modes, &width, &height); + + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); +} + +static void +monitor_switch_active_cb (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + CcDisplayPanel *self = data; + gboolean value; + + if (!self->priv->current_output) + return; + + value = gtk_switch_get_active (GTK_SWITCH (object)); + + if (value) + { + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + select_resolution_for_current_output (self); + } + else + { + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + } + + rebuild_gui (self); + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +realign_outputs_after_resolution_change (CcDisplayPanel *self, GnomeRROutputInfo *output_that_changed, int old_width, int old_height) +{ + /* We find the outputs that were below or to the right of the output that + * changed, and realign them; we also do that for outputs that shared the + * right/bottom edges with the output that changed. The outputs that are + * above or to the left of that output don't need to change. + */ + + int i; + int old_right_edge, old_bottom_edge; + int dx, dy; + int x, y, width, height; + GnomeRROutputInfo **outputs; + + g_assert (self->priv->current_configuration != NULL); + + gnome_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height); + + if (width == old_width && height == old_height) + return; + + old_right_edge = x + old_width; + old_bottom_edge = y + old_height; + + dx = width - old_width; + dy = height - old_height; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; i++) + { + int output_x, output_y; + int output_width, output_height; + + if (outputs[i] == output_that_changed || !gnome_rr_output_info_is_connected (outputs[i])) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (output_x >= old_right_edge) + output_x += dx; + else if (output_x + output_width == old_right_edge) + output_x = x + width - output_width; + + if (output_y >= old_bottom_edge) + output_y += dy; + else if (output_y + output_height == old_bottom_edge) + output_y = y + height - output_height; + + gnome_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height); + } +} + +static void +on_resolution_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + int old_width, old_height; + int x,y; + int width; + int height; + + if (!self->priv->current_output) + return; + + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, &old_width, &old_height); + + if (get_mode (self->priv->resolution_combo, &width, &height, NULL, NULL)) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + + if (width == 0 || height == 0) + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + else + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + } + + realign_outputs_after_resolution_change (self, self->priv->current_output, old_width, old_height); + + rebuild_rotation_combo (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +lay_out_outputs_horizontally (CcDisplayPanel *self) +{ + int i; + int x; + GnomeRROutputInfo **outputs; + + /* Lay out all the monitors horizontally when "mirror screens" is turned + * off, to avoid having all of them overlapped initially. We put the + * outputs turned off on the right-hand side. + */ + + x = 0; + + /* First pass, all "on" outputs */ + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + + /* Second pass, all the black screens */ + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + +} + +/* FIXME: this function is copied from gnome-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c. + * Do we need to put this function in gnome-desktop for public use? + */ +static gboolean +get_clone_size (GnomeRRScreen *screen, int *width, int *height) +{ + GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); + int best_w, best_h; + int i; + + best_w = 0; + best_h = 0; + + for (i = 0; modes[i] != NULL; ++i) { + GnomeRRMode *mode = modes[i]; + int w, h; + + w = gnome_rr_mode_get_width (mode); + h = gnome_rr_mode_get_height (mode); + + if (w * h > best_w * best_h) { + best_w = w; + best_h = h; + } + } + + if (best_w > 0 && best_h > 0) { + if (width) + *width = best_w; + if (height) + *height = best_h; + + return TRUE; + } + + return FALSE; +} + +static gboolean +output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height) +{ + GnomeRROutput *output; + GnomeRRMode **modes; + int i; + + if (!gnome_rr_output_info_is_connected (info)) + return FALSE; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, gnome_rr_output_info_get_name (info)); + if (!output) + return FALSE; + + modes = gnome_rr_output_list_modes (output); + + for (i = 0; modes[i]; i++) { + if (gnome_rr_mode_get_width (modes[i]) == width + && gnome_rr_mode_get_height (modes[i]) == height) + return TRUE; + } + + return FALSE; +} + +static void +on_clone_changed (GtkWidget *box, gpointer data) +{ + CcDisplayPanel *self = data; + + gnome_rr_config_set_clone (self->priv->current_configuration, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox))); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + int i; + int width, height; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + self->priv->current_output = outputs[i]; + break; + } + } + + /* Turn on all the connected screens that support the best clone mode. + * The user may hit "Mirror displays", but he shouldn't have to turn on + * all the required outputs as well. + */ + + get_clone_size (self->priv->screen, &width, &height); + + for (i = 0; outputs[i]; i++) { + int x, y; + if (output_info_supports_mode (self, outputs[i], width, height)) { + gnome_rr_output_info_set_active (outputs[i], TRUE); + gnome_rr_output_info_get_geometry (outputs[i], &x, &y, NULL, NULL); + gnome_rr_output_info_set_geometry (outputs[i], x, y, width, height); + } + } + } + else + { + if (output_overlaps (self->priv->current_output, self->priv->current_configuration)) + lay_out_outputs_horizontally (self); + } + + rebuild_gui (self); +} + +static void +apply_rotation_to_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + GnomeRRRotation rotation; + + rotation = gnome_rr_output_info_get_rotation (output); + if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270)) + { + int tmp; + tmp = *h; + *h = *w; + *w = tmp; + } +} + +static void +get_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + if (gnome_rr_output_info_is_active (output)) + { + gnome_rr_output_info_get_geometry (output, NULL, NULL, w, h); + } + else + { + *h = gnome_rr_output_info_get_preferred_height (output); + *w = gnome_rr_output_info_get_preferred_width (output); + } + + apply_rotation_to_geometry (output, w, h); +} + +#define SPACE 15 +#define MARGIN 15 + +static GList * +list_connected_outputs (CcDisplayPanel *self, int *total_w, int *total_h) +{ + int i, dummy; + GList *result = NULL; + GnomeRROutputInfo **outputs; + + if (!total_w) + total_w = &dummy; + if (!total_h) + total_h = &dummy; + + *total_w = 0; + *total_h = 0; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + int w, h; + + result = g_list_prepend (result, outputs[i]); + + get_geometry (outputs[i], &w, &h); + + *total_w += w; + *total_h += h; + } + } + + return g_list_reverse (result); +} + +static int +get_n_connected (CcDisplayPanel *self) +{ + GList *connected_outputs = list_connected_outputs (self, NULL, NULL); + int n = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + return n; +} + +static double +compute_scale (CcDisplayPanel *self) +{ + int available_w, available_h; + int total_w, total_h; + int n_monitors; + GdkRectangle viewport; + GList *connected_outputs; + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + + connected_outputs = list_connected_outputs (self, &total_w, &total_h); + + n_monitors = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; + available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; + + return MIN ((double)available_w / total_w, (double)available_h / total_h); +} + +typedef struct Edge +{ + GnomeRROutputInfo *output; + int x1, y1; + int x2, y2; +} Edge; + +typedef struct Snap +{ + Edge *snapper; /* Edge that should be snapped */ + Edge *snappee; + int dy, dx; +} Snap; + +static void +add_edge (GnomeRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges) +{ + Edge e; + + e.x1 = x1; + e.x2 = x2; + e.y1 = y1; + e.y2 = y2; + e.output = output; + + g_array_append_val (edges, e); +} + +static void +list_edges_for_output (GnomeRROutputInfo *output, GArray *edges) +{ + int x, y, w, h; + + gnome_rr_output_info_get_geometry (output, &x, &y, &w, &h); + + apply_rotation_to_geometry (output, &w, &h); + + /* Top, Bottom, Left, Right */ + add_edge (output, x, y, x + w, y, edges); + add_edge (output, x, y + h, x + w, y + h, edges); + add_edge (output, x, y, x, y + h, edges); + add_edge (output, x + w, y, x + w, y + h, edges); +} + +static void +list_edges (GnomeRRConfig *config, GArray *edges) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + list_edges_for_output (outputs[i], edges); + } +} + +static gboolean +overlap (int s1, int e1, int s2, int e2) +{ + return (!(e1 < s2 || s1 >= e2)); +} + +static gboolean +horizontal_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) + return FALSE; + + return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); +} + +static gboolean +vertical_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) + return FALSE; + + return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); +} + +static void +add_snap (GArray *snaps, Snap snap) +{ + if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) + g_array_append_val (snaps, snap); +} + +static void +add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) +{ + Snap snap; + + snap.snapper = snapper; + snap.snappee = snappee; + + if (horizontal_overlap (snapper, snappee)) + { + snap.dx = 0; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + } + else if (vertical_overlap (snapper, snappee)) + { + snap.dy = 0; + snap.dx = snappee->x1 - snapper->x1; + + add_snap (snaps, snap); + } + + /* Corner snaps */ + /* 1->1 */ + snap.dx = snappee->x1 - snapper->x1; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + + /* 1->2 */ + snap.dx = snappee->x2 - snapper->x1; + snap.dy = snappee->y2 - snapper->y1; + + add_snap (snaps, snap); + + /* 2->2 */ + snap.dx = snappee->x2 - snapper->x2; + snap.dy = snappee->y2 - snapper->y2; + + add_snap (snaps, snap); + + /* 2->1 */ + snap.dx = snappee->x1 - snapper->x2; + snap.dy = snappee->y1 - snapper->y2; + + add_snap (snaps, snap); +} + +static void +list_snaps (GnomeRROutputInfo *output, GArray *edges, GArray *snaps) +{ + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + if (edge->output != output) + add_edge_snaps (output_edge, edge, snaps); + } + } + } +} + +#if 0 +static void +print_edge (Edge *edge) +{ + g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); +} +#endif + +static gboolean +corner_on_edge (int x, int y, Edge *e) +{ + if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) + return TRUE; + + if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) + return TRUE; + + return FALSE; +} + +static gboolean +edges_align (Edge *e1, Edge *e2) +{ + if (corner_on_edge (e1->x1, e1->y1, e2)) + return TRUE; + + if (corner_on_edge (e2->x1, e2->y1, e1)) + return TRUE; + + return FALSE; +} + +static gboolean +output_is_aligned (GnomeRROutputInfo *output, GArray *edges) +{ + gboolean result = FALSE; + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + /* We are aligned if an output edge matches + * an edge of another output + */ + if (edge->output != output_edge->output) + { + if (edges_align (output_edge, edge)) + { + result = TRUE; + goto done; + } + } + } + } + } + done: + + return result; +} + +static void +get_output_rect (GnomeRROutputInfo *output, GdkRectangle *rect) +{ + gnome_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); + + apply_rotation_to_geometry (output, &rect->width, &rect->height); +} + +static gboolean +output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config) +{ + int i; + GdkRectangle output_rect; + GnomeRROutputInfo **outputs; + + g_assert (output != NULL); + + get_output_rect (output, &output_rect); + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (outputs[i] != output && gnome_rr_output_info_is_connected (outputs[i])) + { + GdkRectangle other_rect; + + get_output_rect (outputs[i], &other_rect); + if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gnome_rr_config_is_aligned (GnomeRRConfig *config, GArray *edges) +{ + int i; + gboolean result = TRUE; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + if (!output_is_aligned (outputs[i], edges)) + return FALSE; + + if (output_overlaps (outputs[i], config)) + return FALSE; + } + } + + return result; +} + +static gboolean +is_corner_snap (const Snap *s) +{ + return s->dx != 0 && s->dy != 0; +} + +static int +compare_snaps (gconstpointer v1, gconstpointer v2) +{ + const Snap *s1 = v1; + const Snap *s2 = v2; + int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); + int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); + int d; + + d = sv1 - sv2; + + /* This snapping algorithm is good enough for rock'n'roll, but + * this is probably a better: + * + * First do a horizontal/vertical snap, then + * with the new coordinates from that snap, + * do a corner snap. + * + * Right now, it's confusing that corner snapping + * depends on the distance in an axis that you can't actually see. + * + */ + if (d == 0) + { + if (is_corner_snap (s1) && !is_corner_snap (s2)) + return -1; + else if (is_corner_snap (s2) && !is_corner_snap (s1)) + return 1; + else + return 0; + } + else + { + return d; + } +} + +/* Sets a mouse cursor for a widget's window. As a hack, you can pass + * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's + * window's cursor to its default). + */ +static void +set_cursor (GtkWidget *widget, GdkCursorType type) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (type == GDK_BLANK_CURSOR) + cursor = NULL; + else + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); + + window = gtk_widget_get_window (widget); + + if (window) + gdk_window_set_cursor (window, cursor); + + if (cursor) + g_object_unref (cursor); +} + +static void +set_top_bar_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Drag to change primary display."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +on_top_bar_event (FooScrollArea *area, + FooScrollAreaEvent *event, + CcDisplayPanel *self) +{ + /* Ignore drops */ + if (event->type == FOO_DROP) + return; + + /* If the mouse is inside the top bar, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_HAND1); + + if (event->type == FOO_BUTTON_PRESS) + { + rebuild_gui (self); + set_top_bar_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + self->priv->dragging_top_bar = TRUE; + foo_scroll_area_begin_grab (area, (FooScrollAreaEventFunc) on_top_bar_event, self); + } + + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + self->priv->dragging_top_bar = FALSE; + set_top_bar_tooltip (self, FALSE); + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +set_monitors_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Select a monitor to change its properties; drag it to rearrange its placement."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +set_primary_output (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + int i; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); + + gtk_widget_queue_draw (WID ("self->priv->area")); + /* refresh the combobox */ + refresh_unity_launcher_placement (self); +} + +static void +on_output_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + GnomeRROutputInfo *output = data; + CcDisplayPanel *self = g_object_get_data (G_OBJECT (area), "panel"); + + if (event->type == FOO_DRAG_HOVER) + { + if (gnome_rr_output_info_is_active (output) && self->priv->dragging_top_bar) + set_primary_output (self, output); + return; + } + if (event->type == FOO_DROP) + { + /* Activate new primary? */ + return; + } + + /* If the mouse is inside the outputs, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_FLEUR); + + if (event->type == FOO_BUTTON_PRESS) + { + GrabInfo *info; + + self->priv->current_output = output; + + rebuild_gui (self); + set_monitors_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + int output_x, output_y; + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + + foo_scroll_area_begin_grab (area, on_output_event, data); + + info = g_new0 (GrabInfo, 1); + info->grab_x = event->x; + info->grab_y = event->y; + info->output_x = output_x; + info->output_y = output_y; + + g_object_set_data (G_OBJECT (output), "grab-info", info); + } + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); + double scale = compute_scale (self); + int old_x, old_y; + int width, height; + int new_x, new_y; + int i; + GArray *edges, *snaps, *new_edges; + + gnome_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height); + new_x = info->output_x + (event->x - info->grab_x) / scale; + new_y = info->output_y + (event->y - info->grab_y) / scale; + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); + new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + list_edges (self->priv->current_configuration, edges); + list_snaps (output, edges, snaps); + + g_array_sort (snaps, compare_snaps); + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + for (i = 0; i < snaps->len; ++i) + { + Snap *snap = &(g_array_index (snaps, Snap, i)); + GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + gnome_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height); + + g_array_set_size (new_edges, 0); + list_edges (self->priv->current_configuration, new_edges); + + if (gnome_rr_config_is_aligned (self->priv->current_configuration, new_edges)) + { + g_array_free (new_edges, TRUE); + break; + } + else + { + gnome_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height); + } + } + + g_array_free (new_edges, TRUE); + g_array_free (snaps, TRUE); + g_array_free (edges, TRUE); + + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + set_monitors_tooltip (self, FALSE); + + g_free (g_object_get_data (G_OBJECT (output), "grab-info")); + g_object_set_data (G_OBJECT (output), "grab-info", NULL); + +#if 0 + g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); +#endif + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +on_canvas_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + /* If the mouse exits the outputs, reset the cursor to the default. See + * on_output_event() for where we set the cursor to the movement cursor if + * it is over one of the outputs. + */ + set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); +} + +static PangoLayout * +get_display_name (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + PangoLayout *layout; + char *text; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + text = mirror_monitor_name (); + else + text = g_strdup (gnome_rr_output_info_get_display_name (output)); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + return layout; +} + +static void +paint_background (FooScrollArea *area, + cairo_t *cr) +{ + GdkRectangle viewport; + GtkWidget *widget; + GtkStyleContext *context; + GdkRGBA fg, bg; + + widget = GTK_WIDGET (area); + + foo_scroll_area_get_viewport (area, &viewport); + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg); + + cairo_set_source_rgba (cr, + (fg.red + bg.red) / 2, + (fg.green + bg.green) / 2, + (fg.blue + bg.blue) / 2, + (fg.alpha + bg.alpha) / 2); + + cairo_rectangle (cr, + viewport.x, viewport.y, + viewport.width, viewport.height); + + cairo_fill_preserve (cr); + + foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); + + cairo_set_source_rgba (cr, + 0.7 * bg.red, + 0.7 * bg.green, + 0.7 * bg.blue, + 0.7 * bg.alpha); + + cairo_stroke (cr); +} + +static void +color_shade (double *r, + double *g, + double *b, + double k) +{ + double h, s, v; + + gtk_rgb_to_hsv (*r, *g, *b, &h, &s, &v); + + s *= k; + if (s > 1.0) + s = 1.0; + else if (s < 0.0) + s = 0.0; + + v *= k; + if (v > 1.0) + v = 1.0; + else if (v < 0.0) + v = 0.0; + + gtk_hsv_to_rgb (h, s, v, r, g, b); +} + +static void +paint_output (CcDisplayPanel *self, cairo_t *cr, int i) +{ + int w, h; + double scale = compute_scale (self); + double x, y; + int output_x, output_y; + GnomeRRRotation rotation; + int total_w, total_h; + GList *connected_outputs = list_connected_outputs (self, &total_w, &total_h); + GnomeRROutputInfo *output = g_list_nth (connected_outputs, i)->data; + PangoLayout *layout = get_display_name (self, output); + PangoRectangle ink_extent, log_extent; + GdkRectangle viewport; + GdkRGBA output_color; + double r, g, b; + double available_w; + double factor; + + cairo_save (cr); + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + get_geometry (output, &w, &h); + +#if 0 + g_debug ("%s (%p) geometry %d %d %d primary=%d", output->name, output->name, + w, h, output->rate, output->primary); +#endif + + viewport.height -= 2 * MARGIN; + viewport.width -= 2 * MARGIN; + + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; + y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; + +#if 0 + g_debug ("scaled: %f %f", x, y); + + g_debug ("scale: %f", scale); + + g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5); +#endif + + cairo_translate (cr, + x + (w * scale + 0.5) / 2, + y + (h * scale + 0.5) / 2); + + /* rotation is already applied in get_geometry */ + + rotation = gnome_rr_output_info_get_rotation (output); + if (rotation & GNOME_RR_REFLECT_X) + cairo_scale (cr, -1, 1); + + if (rotation & GNOME_RR_REFLECT_Y) + cairo_scale (cr, 1, -1); + + cairo_translate (cr, + - x - (w * scale + 0.5) / 2, + - y - (h * scale + 0.5) / 2); + + if (output == self->priv->current_output) + { + GtkStyleContext *context; + GdkRGBA color; + + context = gtk_widget_get_style_context (self->priv->area); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); + + cairo_rectangle (cr, x - 2, y - 2, w * scale + 0.5 + 4, h * scale + 0.5 + 4); + + cairo_set_line_width (cr, 4); + cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5); + cairo_stroke (cr); + } + + cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); + cairo_clip_preserve (cr); + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); + r = output_color.red; + g = output_color.green; + b = output_color.blue; + + if (!gnome_rr_output_info_is_active (output)) + { + /* If the output is turned off, just darken the selected color */ + color_shade (&r, &g, &b, 0.4); + } + + cairo_set_source_rgba (cr, r, g, b, 1.0); + + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, on_output_event, output); + cairo_fill (cr); + + cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + + cairo_stroke (cr); + cairo_set_line_width (cr, 2); + + cairo_save (cr); + + layout_set_font (layout, "Sans 10"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */ + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + ((h * scale + 0.5) - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + if (gnome_rr_output_info_is_active (output)) + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + else + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + cairo_restore (cr); + + /* Only display a launcher on all or primary monitor */ + if (is_unity_session ()) + { + if (gnome_rr_output_info_is_active (output) && (unity_launcher_on_all_monitors (self->priv->unity_settings) || gnome_rr_output_info_get_primary (output))) + { + cairo_rectangle (cr, x, y, 10, h * scale + 0.5); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + cairo_rectangle (cr, x + 1, y + 6, 8, 8); + cairo_rectangle (cr, x + 1, y + 16, 8, 8); + cairo_rectangle (cr, x + 1, y + 26, 8, 8); + cairo_rectangle (cr, x + 1, y + 36, 8, 8); + cairo_rectangle (cr, x + 1, y + h * scale + 0.5 - 10, 8, 8); + cairo_fill (cr); + } + } + + if (gnome_rr_output_info_get_primary (output) && !is_unity_session ()) + { + const char *clock_format; + char *text; + gboolean use_24; + GDateTime *dt; + GDesktopClockFormat value; + + /* top bar */ + cairo_rectangle (cr, x, y, w * scale + 0.5, TOP_BAR_HEIGHT); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + + cairo_fill (cr); + + /* clock */ + value = g_settings_get_enum (self->priv->clock_settings, CLOCK_FORMAT_KEY); + use_24 = value == G_DESKTOP_CLOCK_FORMAT_24H; + if (use_24) + clock_format = _("%a %R"); + else + clock_format = _("%a %l:%M %p"); + + dt = g_date_time_new_now_local (); + text = g_date_time_format (dt, clock_format); + g_date_time_unref (dt); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + layout_set_font (layout, "Sans 4"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + (TOP_BAR_HEIGHT - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + } + + cairo_restore (cr); +} + +static void +on_area_paint (FooScrollArea *area, + cairo_t *cr, + gpointer data) +{ + CcDisplayPanel *self = data; + GList *connected_outputs = NULL; + GList *list; + + paint_background (area, cr); + + if (!self->priv->current_configuration) + return; + + connected_outputs = list_connected_outputs (self, NULL, NULL); + + for (list = connected_outputs; list != NULL; list = list->next) + { + paint_output (self, cr, g_list_position (connected_outputs, list)); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + break; + } +} + +static void +make_text_combo (GtkWidget *widget, int sort_column) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkListStore *store = gtk_list_store_new ( + NUM_COLS, + G_TYPE_STRING, /* Text */ + G_TYPE_INT, /* Width */ + G_TYPE_INT, /* Height */ + G_TYPE_INT, /* Frequency */ + G_TYPE_INT, /* Width * Height */ + G_TYPE_INT); /* Rotation */ + + GtkCellRenderer *cell; + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget)); + + gtk_combo_box_set_model (box, GTK_TREE_MODEL (store)); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell, + "text", 0, + NULL); + + if (sort_column != -1) + { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + sort_column, + GTK_SORT_DESCENDING); + } +} + +static void +compute_virtual_size_for_configuration (GnomeRRConfig *config, int *ret_width, int *ret_height) +{ + int i; + int width, height; + int output_x, output_y, output_width, output_height; + GnomeRROutputInfo **outputs; + + width = height = 0; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) + { + if (gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + width = MAX (width, output_x + output_width); + height = MAX (height, output_y + output_height); + } + } + + *ret_width = width; + *ret_height = height; +} + +static void +check_required_virtual_size (CcDisplayPanel *self) +{ + int req_width, req_height; + int min_width, max_width; + int min_height, max_height; + + compute_virtual_size_for_configuration (self->priv->current_configuration, &req_width, &req_height); + + gnome_rr_screen_get_ranges (self->priv->screen, &min_width, &max_width, &min_height, &max_height); + +#if 0 + g_debug ("X Server supports:"); + g_debug ("min_width = %d, max_width = %d", min_width, max_width); + g_debug ("min_height = %d, max_height = %d", min_height, max_height); + + g_debug ("Requesting size of %dx%d", req_width, req_height); +#endif + + if (!(min_width <= req_width && req_width <= max_width + && min_height <= req_height && req_height <= max_height)) + { + /* FIXME: present a useful dialog, maybe even before the user tries to Apply */ +#if 0 + g_debug ("Your X server needs a larger Virtual size!"); +#endif + } +} + +static void +begin_version2_apply_configuration (CcDisplayPanel *self, GdkWindow *parent_window, guint32 timestamp) +{ + XID parent_window_xid; + GError *error = NULL; + + parent_window_xid = GDK_WINDOW_XID (parent_window); + + self->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/XRANDR", + "org.gnome.SettingsDaemon.XRANDR_2", + NULL, + &error); + if (self->priv->proxy == NULL) { + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_error_free (error); + return; + } + + g_dbus_proxy_call (self->priv->proxy, + "ApplyConfiguration", + g_variant_new ("(xx)", (gint64) parent_window_xid, (gint64) timestamp), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + apply_configuration_returned_cb, + self); +} + +static void +ensure_current_configuration_is_saved (void) +{ + GnomeRRScreen *rr_screen; + GnomeRRConfig *rr_config; + + /* Normally, gnome_rr_config_save() creates a backup file based on the + * old monitors.xml. However, if *that* file didn't exist, there is + * nothing from which to create a backup. So, here we'll save the + * current/unchanged configuration and then let our caller call + * gnome_rr_config_save() again with the new/changed configuration, so + * that there *will* be a backup file in the end. + */ + + rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL); /* NULL-GError */ + if (!rr_screen) + return; + + rr_config = gnome_rr_config_new_current (rr_screen, NULL); + gnome_rr_config_ensure_primary (rr_config); + gnome_rr_config_save (rr_config, NULL); /* NULL-GError */ + + g_object_unref (rr_config); + g_object_unref (rr_screen); +} + +static void +apply_configuration_returned_cb (GObject *proxy, + GAsyncResult *res, + gpointer data) +{ + CcDisplayPanel *self = data; + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if (error) + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_clear_error (&error); + if (result) + g_variant_unref (result); + + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + + gtk_widget_set_sensitive (self->priv->panel, TRUE); +} + +static gboolean +sanitize_and_save_configuration (CcDisplayPanel *self) +{ + GError *error; + + gnome_rr_config_sanitize (self->priv->current_configuration); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + + check_required_virtual_size (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); + + ensure_current_configuration_is_saved (); + + error = NULL; + if (!gnome_rr_config_save (self->priv->current_configuration, &error)) + { + error_message (self, _("Could not save the monitor configuration"), error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +static void +apply (CcDisplayPanel *self) +{ + GdkWindow *window; + + self->priv->apply_button_clicked_timestamp = gtk_get_current_event_time (); + + if (!sanitize_and_save_configuration (self)) + return; + + g_assert (self->priv->proxy == NULL); + + gtk_widget_set_sensitive (self->priv->panel, FALSE); + + window = gtk_widget_get_window (gtk_widget_get_toplevel (self->priv->panel)); + + begin_version2_apply_configuration (self, window, + self->priv->apply_button_clicked_timestamp); +} + +#if 0 +/* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */ +static gboolean +driver_is_randr_10 (GnomeRRConfig *config) +{ + /* In the Xorg code, see xserver/randr/rrinfo.c:RRScanOldConfig(). It gets + * called when the graphics driver doesn't support RANDR 1.2 yet, just 1.0. + * In that case, the X server's base code (which supports RANDR 1.2) will + * simulate having a single output called "default". For drivers that *do* + * support RANDR 1.2, the separate outputs will be named differently, we + * hope. + * + * This heuristic is courtesy of Dirk Mueller + * + * FIXME: however, we don't even check for XRRQueryVersion() returning 1.2, neither + * here nor in gnome-desktop/libgnomedesktop*.c. Do we need to check for that, + * or is gnome_rr_screen_new()'s return value sufficient? + */ + + return (count_all_outputs (config) == 1 && strcmp (gnome_rr_output_info_get_name (gnome_rr_config_get_outputs (config)[0]), "default") == 0); +} +#endif + +static void +on_detect_displays (GtkWidget *widget, gpointer data) +{ + CcDisplayPanel *self = data; + GError *error; + + error = NULL; + if (!gnome_rr_screen_refresh (self->priv->screen, &error)) { + if (error) { + error_message (self, _("Could not detect displays"), error->message); + g_error_free (error); + } + } +} + +static GnomeRROutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) +{ + int i; + int nearest_index; + int nearest_dist; + GnomeRROutputInfo **outputs; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + int dist_x, dist_y; + int output_x, output_y, output_width, output_height; + + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (x < output_x) + dist_x = output_x - x; + else if (x >= output_x + output_width) + dist_x = x - (output_x + output_width) + 1; + else + dist_x = 0; + + if (y < output_y) + dist_y = output_y - y; + else if (y >= output_y + output_height) + dist_y = y - (output_y + output_height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return outputs[nearest_index]; + else + return NULL; +} + +/* Gets the output that contains the largest intersection with the window. + * Logic stolen from gdk_screen_get_monitor_at_window(). + */ +static GnomeRROutputInfo * +get_output_for_window (GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + GnomeRROutputInfo **outputs; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + GdkRectangle output_rect, intersection; + + gnome_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); + + if (gnome_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +static void +dialog_toplevel_focus_changed (GtkWindow *window, + GParamSpec *pspec, + CcDisplayPanel *self) +{ + if (self->priv->labeler == NULL) + return; + if (gtk_window_has_toplevel_focus (window)) + gnome_rr_labeler_show (self->priv->labeler); + else + gnome_rr_labeler_hide (self->priv->labeler); +} + +static void +on_toplevel_realized (GtkWidget *widget, + CcDisplayPanel *self) +{ + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (widget)); + rebuild_gui (self); +} + +/* We select the current output, i.e. select the one being edited, based on + * which output is showing the configuration dialog. + */ +static void +select_current_output_from_dialog_position (CcDisplayPanel *self) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (self->priv->panel); + + if (gtk_widget_get_realized (toplevel)) { + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (toplevel)); + rebuild_gui (self); + } else { + g_signal_connect (toplevel, "realize", G_CALLBACK (on_toplevel_realized), self); + self->priv->current_output = NULL; + } +} + +/* This is a GtkWidget::map-event handler. We wait for the display-properties + * dialog to be mapped, and then we select the output which corresponds to the + * monitor on which the dialog is being shown. + */ +static gboolean +dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + CcDisplayPanel *self = data; + + select_current_output_from_dialog_position (self); + return FALSE; +} + +static void +stickyedge_widget_refresh (GtkSwitch *switcher, GSettings *settings) +{ + gboolean stickyedge_enabled = g_settings_get_boolean (settings, UNITY_STICKY_EDGE_KEY); + + gtk_switch_set_active (switcher, stickyedge_enabled); +} + +static void +ext_stickyedge_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + stickyedge_widget_refresh (GTK_SWITCH (user_data), settings); +} + +static void +on_stickyedge_changed (GtkSwitch *switcher, GParamSpec *pspec, gpointer user_data) +{ + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gboolean enabled = gtk_switch_get_active (GTK_SWITCH (switcher)); + + /* 3d */ + g_settings_set_boolean (self->priv->unity_settings, UNITY_STICKY_EDGE_KEY, enabled); + /* 2d */ + if (self->priv->unity2d_settings_main) + g_settings_set_boolean (self->priv->unity2d_settings_main, "sticky-edges", enabled); +} + +static gboolean +unity_launcher_on_all_monitors (GSettings *settings) +{ + gint value = g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY); + return (value == 0); +} + +static GdkPixbuf* +get_monitor_pixbuf (CcDisplayPanel *self, GnomeRROutputInfo *output) +{ + GdkRGBA color; + cairo_surface_t *cairo_surface; + cairo_t *cr; + int monitor_width = 30; + int monitor_height = 15; + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); + + cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); + cr = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, color.red, color.green, color.blue); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0, 0, 0, 1.0); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_stroke (cr); + + return gdk_pixbuf_get_from_surface (cairo_get_target (cr), 0, 0, monitor_width, monitor_height); +} + +static void +refresh_unity_launcher_placement (CcDisplayPanel *self) +{ + GtkWidget *launcher_placement_combo = WID ("launcher_placement_combo"); + GtkListStore *liststore; + GtkTreeIter iter; + GList *connected_outputs = NULL; + GList *list; + gboolean launcher_on_all_monitors = unity_launcher_on_all_monitors (self->priv->unity_settings); + gint index_of_primary_screen = 0; + gint i; + + liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "available_launcher_placement_store"); + gtk_list_store_clear (liststore); + + connected_outputs = list_connected_outputs (self, NULL, NULL); + for (list = connected_outputs, i = 0; list != NULL; list = list->next) + { + char *monitor_name; + GdkPixbuf *monitor_pixbuf; + GnomeRROutputInfo *output = list->data; + + if (!gnome_rr_output_info_is_active (output)) + continue; + + gtk_list_store_append (liststore, &iter); + monitor_name = g_strdup (gnome_rr_output_info_get_display_name (output)); + monitor_pixbuf = get_monitor_pixbuf (self, output); + + gtk_list_store_set (liststore, &iter, 0, monitor_pixbuf, 1, monitor_name, -1); + + /* select it if primary and only one launcher */ + if (gnome_rr_output_info_get_primary (output) && (!launcher_on_all_monitors)) + index_of_primary_screen = i; + i++; + + g_object_unref (monitor_pixbuf); + g_free (monitor_name); + } + + // FIXME: check autosort? + gtk_list_store_append (liststore, &iter); + gtk_list_store_set (liststore, &iter, 0, NULL, 1, _("All displays"), -1); + + if (launcher_on_all_monitors) + index_of_primary_screen = i; + + gtk_combo_box_set_active (GTK_COMBO_BOX (launcher_placement_combo), index_of_primary_screen); +} + +static gboolean +switcher_set_to_launcher_on_all_monitors (CcDisplayPanel *self) +{ + GtkComboBox *combo = GTK_COMBO_BOX (WID ("launcher_placement_combo")); + gint active = gtk_combo_box_get_active (combo); + gint number_items = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), + NULL); + return (active == number_items - 1); +} + +static void +ext_launcher_placement_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + // add some crazyness as 2d/3d are not using the same keys + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gint launcher_unity_value = 0; + + // two options support: all monitors (0)i or just primary desktop (hence set to 1, not any other number) + if (! switcher_set_to_launcher_on_all_monitors (self)) + launcher_unity_value = 1; + + if (g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY) != launcher_unity_value) + refresh_unity_launcher_placement (self); +} + +static void +on_launcher_placement_combo_changed (GtkComboBox *combo, CcDisplayPanel *self) +{ + gint active = gtk_combo_box_get_active (combo); + gint i; + gint index_on_combo = 0; + + if (active < 0) + return; + gint value = 0; + gboolean on_all_monitors = switcher_set_to_launcher_on_all_monitors (self); + + if (!on_all_monitors) { + value = 1; + // set the primary output if needed + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + GnomeRROutputInfo *output = outputs[i]; + if (!gnome_rr_output_info_is_active (output)) + continue; + + if ((active == index_on_combo) && !gnome_rr_output_info_get_primary (output)) + { + set_primary_output (self, output); + break; + } + index_on_combo++; + } + } + + /* 3d */ + if (self->priv->unity_settings) + g_settings_set_int (self->priv->unity_settings, UNITY_LAUNCHER_ALL_MONITORS_KEY, value); + /* 2d */ + if (self->priv->unity2d_settings_launcher) + g_settings_set_boolean (self->priv->unity2d_settings_launcher, "only-one-launcher", !on_all_monitors); +} + +static void +setup_unity_settings (CcDisplayPanel *self) +{ + const gchar * const *schemas; + + /* Only use the unity-2d schema if it's installed */ + schemas = g_settings_list_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY2D_GSETTINGS_LAUNCHER) == 0) + { + self->priv->unity2d_settings_main = g_settings_new (UNITY2D_GSETTINGS_MAIN); + self->priv->unity2d_settings_launcher = g_settings_new (UNITY2D_GSETTINGS_LAUNCHER); + break; + } + schemas++; + } + schemas = g_settings_list_relocatable_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY_GSETTINGS_SCHEMA) == 0) + { + self->priv->unity_settings = g_settings_new_with_path (UNITY_GSETTINGS_SCHEMA, UNITY_GSETTINGS_PATH); + break; + } + schemas++; + } + + if (!self->priv->unity_settings) + return; + + GtkWidget *sticky_edge_switch = WID ("stickyedge_switch"); + g_signal_connect (sticky_edge_switch, "notify::active", + G_CALLBACK (on_stickyedge_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_STICKY_EDGE_KEY, + G_CALLBACK (ext_stickyedge_changed_callback), sticky_edge_switch); + stickyedge_widget_refresh (GTK_SWITCH (sticky_edge_switch), self->priv->unity_settings); + + g_signal_connect (G_OBJECT (WID ("launcher_placement_combo")), "changed", + G_CALLBACK (on_launcher_placement_combo_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_LAUNCHER_ALL_MONITORS_KEY, + G_CALLBACK (ext_launcher_placement_changed_callback), self); +} + +static void +cc_display_panel_init (CcDisplayPanel *self) +{ +} + +static GObject * +cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) +{ + GtkBuilder *builder; + GtkWidget *align; + GError *error; + GObject *obj; + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + gchar *objects[] = {"display-panel", "available_launcher_placement_store", NULL}; + + obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); + self = CC_DISPLAY_PANEL (obj); + self->priv = DISPLAY_PANEL_PRIVATE (self); + + error = NULL; + self->priv->builder = builder = gtk_builder_new (); + + if (!gtk_builder_add_objects_from_file (builder, UIDIR "/display-capplet.ui", objects, &error)) + { + g_warning ("Could not parse UI definition: %s", error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); + g_signal_connect (self->priv->screen, "changed", G_CALLBACK (on_screen_changed), self); + if (!self->priv->screen) + { + error_message (NULL, _("Could not get screen information"), error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->clock_settings = g_settings_new (CLOCK_SCHEMA); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + self->priv->focus_id = g_signal_connect (toplevel, "notify::has-toplevel-focus", + G_CALLBACK (dialog_toplevel_focus_changed), self); + + self->priv->panel = WID ("display-panel"); + g_signal_connect_after (self->priv->panel, "show", + G_CALLBACK (dialog_map_event_cb), self); + + self->priv->current_monitor_event_box = WID ("current_monitor_event_box"); + self->priv->current_monitor_label = WID ("current_monitor_label"); + + self->priv->monitor_switch = WID ("monitor_switch"); + g_signal_connect (self->priv->monitor_switch, "notify::active", + G_CALLBACK (monitor_switch_active_cb), self); + + self->priv->resolution_combo = WID ("resolution_combo"); + g_signal_connect (self->priv->resolution_combo, "changed", + G_CALLBACK (on_resolution_changed), self); + + self->priv->rotation_combo = WID ("rotation_combo"); + g_signal_connect (self->priv->rotation_combo, "changed", + G_CALLBACK (on_rotation_changed), self); + + self->priv->clone_checkbox = WID ("clone_checkbox"); + g_signal_connect (self->priv->clone_checkbox, "toggled", + G_CALLBACK (on_clone_changed), self); + + self->priv->clone_label = WID ("clone_resolution_warning_label"); + + g_signal_connect (WID ("detect_displays_button"), + "clicked", G_CALLBACK (on_detect_displays), self); + + make_text_combo (self->priv->resolution_combo, 4); + make_text_combo (self->priv->rotation_combo, -1); + + /* Scroll Area */ + self->priv->area = (GtkWidget *)foo_scroll_area_new (); + + g_object_set_data (G_OBJECT (self->priv->area), "panel", self); + + set_monitors_tooltip (self, FALSE); + + /* FIXME: this should be computed dynamically */ + foo_scroll_area_set_min_size (FOO_SCROLL_AREA (self->priv->area), 0, 200); + gtk_widget_show (self->priv->area); + g_signal_connect (self->priv->area, "paint", + G_CALLBACK (on_area_paint), self); + g_signal_connect (self->priv->area, "viewport_changed", + G_CALLBACK (on_viewport_changed), self); + + align = WID ("align"); + + gtk_container_add (GTK_CONTAINER (align), self->priv->area); + + on_screen_changed (self->priv->screen, self); + + g_signal_connect_swapped (WID ("apply_button"), + "clicked", G_CALLBACK (apply), self); + + /* Unity settings */ + if (is_unity_session ()) + setup_unity_settings (self); + else + { + gtk_widget_hide (WID ("unity_launcher_placement_sep")); + gtk_widget_hide (WID ("launcher_placement_label")); + gtk_widget_hide (WID ("sticky_edge_label")); + gtk_widget_hide (WID ("launcher_placement_combo")); + gtk_widget_hide (WID ("stickyedge_switch")); + } + + gtk_widget_show (self->priv->panel); + gtk_container_add (GTK_CONTAINER (self), self->priv->panel); + + return obj; +} + +void +cc_display_panel_register (GIOModule *module) +{ + cc_display_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_DISPLAY_PANEL, + "display", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/git_add_printer_crash.patch/panels/printers/pp-new-printer.c gnome-control-center-3.6.3/.pc/git_add_printer_crash.patch/panels/printers/pp-new-printer.c --- gnome-control-center-3.6.3/.pc/git_add_printer_crash.patch/panels/printers/pp-new-printer.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_add_printer_crash.patch/panels/printers/pp-new-printer.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1444 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2012 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Marek Kasik + */ + +#include "pp-new-printer.h" + +#include +#include + +#include "pp-utils.h" +#include "pp-maintenance-command.h" + +#define PACKAGE_KIT_BUS "org.freedesktop.PackageKit" +#define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit" +#define PACKAGE_KIT_MODIFY_IFACE "org.freedesktop.PackageKit.Modify" +#define PACKAGE_KIT_QUERY_IFACE "org.freedesktop.PackageKit.Query" + +#define DBUS_TIMEOUT 120000 +#define DBUS_TIMEOUT_LONG 600000 + +#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5) +#define HAVE_CUPS_1_6 1 +#endif + +#ifndef HAVE_CUPS_1_6 +#define ippGetState(ipp) ipp->state +#endif + +struct _PpNewPrinterPrivate +{ + gchar *name; + gchar *original_name; + gchar *device_uri; + gchar *device_id; + gchar *ppd_name; + gchar *ppd_file_name; + gchar *info; + gchar *location; + gchar *make_and_model; + gchar *host_name; + gint host_port; + gboolean is_network_device; + guint window_id; + gboolean unlink_ppd_file; + + GSimpleAsyncResult *res; + GCancellable *cancellable; +}; + +G_DEFINE_TYPE (PpNewPrinter, pp_new_printer, G_TYPE_OBJECT); + +enum { + PROP_0 = 0, + PROP_NAME, + PROP_ORIGINAL_NAME, + PROP_DEVICE_URI, + PROP_DEVICE_ID, + PROP_PPD_NAME, + PROP_PPD_FILE_NAME, + PROP_INFO, + PROP_LOCATION, + PROP_MAKE_AND_MODEL, + PROP_HOST_NAME, + PROP_HOST_PORT, + PROP_IS_NETWORK_DEVICE, + PROP_WINDOW_ID +}; + +static void +pp_new_printer_finalize (GObject *object) +{ + PpNewPrinterPrivate *priv; + + priv = PP_NEW_PRINTER (object)->priv; + + if (priv->unlink_ppd_file && priv->ppd_file_name) + g_unlink (priv->ppd_file_name); + + g_clear_pointer (&priv->name, g_free); + g_clear_pointer (&priv->original_name, g_free); + g_clear_pointer (&priv->device_uri, g_free); + g_clear_pointer (&priv->device_id, g_free); + g_clear_pointer (&priv->ppd_name, g_free); + g_clear_pointer (&priv->ppd_file_name, g_free); + g_clear_pointer (&priv->info, g_free); + g_clear_pointer (&priv->location, g_free); + g_clear_pointer (&priv->make_and_model, g_free); + g_clear_pointer (&priv->host_name, g_free); + + if (priv->res) + g_object_unref (priv->res); + + if (priv->cancellable) + g_object_unref (priv->cancellable); + + G_OBJECT_CLASS (pp_new_printer_parent_class)->finalize (object); +} + +static void +pp_new_printer_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *param_spec) +{ + PpNewPrinter *self; + + self = PP_NEW_PRINTER (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, self->priv->name); + break; + case PROP_ORIGINAL_NAME: + g_value_set_string (value, self->priv->original_name); + break; + case PROP_DEVICE_URI: + g_value_set_string (value, self->priv->device_uri); + break; + case PROP_DEVICE_ID: + g_value_set_string (value, self->priv->device_id); + break; + case PROP_PPD_NAME: + g_value_set_string (value, self->priv->ppd_name); + break; + case PROP_PPD_FILE_NAME: + g_value_set_string (value, self->priv->ppd_file_name); + break; + case PROP_INFO: + g_value_set_string (value, self->priv->info); + break; + case PROP_LOCATION: + g_value_set_string (value, self->priv->location); + break; + case PROP_MAKE_AND_MODEL: + g_value_set_string (value, self->priv->make_and_model); + break; + case PROP_HOST_NAME: + g_value_set_string (value, self->priv->host_name); + break; + case PROP_HOST_PORT: + g_value_set_int (value, self->priv->host_port); + break; + case PROP_IS_NETWORK_DEVICE: + g_value_set_boolean (value, self->priv->is_network_device); + break; + case PROP_WINDOW_ID: + g_value_set_int (value, self->priv->window_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +pp_new_printer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *param_spec) +{ + PpNewPrinter *self = PP_NEW_PRINTER (object); + + switch (prop_id) + { + case PROP_NAME: + g_free (self->priv->name); + self->priv->name = g_value_dup_string (value); + break; + case PROP_ORIGINAL_NAME: + g_free (self->priv->original_name); + self->priv->original_name = g_value_dup_string (value); + break; + case PROP_DEVICE_URI: + g_free (self->priv->device_uri); + self->priv->device_uri = g_value_dup_string (value); + break; + case PROP_DEVICE_ID: + g_free (self->priv->device_id); + self->priv->device_id = g_value_dup_string (value); + break; + case PROP_PPD_NAME: + g_free (self->priv->ppd_name); + self->priv->ppd_name = g_value_dup_string (value); + break; + case PROP_PPD_FILE_NAME: + g_free (self->priv->ppd_file_name); + self->priv->ppd_file_name = g_value_dup_string (value); + break; + case PROP_INFO: + g_free (self->priv->info); + self->priv->info = g_value_dup_string (value); + break; + case PROP_LOCATION: + g_free (self->priv->location); + self->priv->location = g_value_dup_string (value); + break; + case PROP_MAKE_AND_MODEL: + g_free (self->priv->make_and_model); + self->priv->make_and_model = g_value_dup_string (value); + break; + case PROP_HOST_NAME: + g_free (self->priv->host_name); + self->priv->host_name = g_value_dup_string (value); + break; + case PROP_HOST_PORT: + self->priv->host_port = g_value_get_int (value); + break; + case PROP_IS_NETWORK_DEVICE: + self->priv->is_network_device = g_value_get_boolean (value); + break; + case PROP_WINDOW_ID: + self->priv->window_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +pp_new_printer_class_init (PpNewPrinterClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PpNewPrinterPrivate)); + + gobject_class->set_property = pp_new_printer_set_property; + gobject_class->get_property = pp_new_printer_get_property; + + gobject_class->finalize = pp_new_printer_finalize; + + g_object_class_install_property (gobject_class, PROP_NAME, + g_param_spec_string ("name", + "Name", + "The new printer's name", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_ORIGINAL_NAME, + g_param_spec_string ("original-name", + "Original name", + "Original name of the new printer", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_DEVICE_URI, + g_param_spec_string ("device-uri", + "Device URI", + "The new printer's device URI", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_DEVICE_ID, + g_param_spec_string ("device-id", + "DeviceID", + "The new printer's DeviceID", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PPD_NAME, + g_param_spec_string ("ppd-name", + "PPD name", + "Name of PPD for the new printer", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PPD_FILE_NAME, + g_param_spec_string ("ppd-file-name", + "PPD file name", + "PPD file for the new printer", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_INFO, + g_param_spec_string ("info", + "Printer info", + "The new printer's info", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", + "Printer location", + "The new printer's location", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_MAKE_AND_MODEL, + g_param_spec_string ("make-and-model", + "Printer make and model", + "The new printer's make and model", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_HOST_NAME, + g_param_spec_string ("host-name", + "Hostname", + "The new printer's hostname", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_HOST_PORT, + g_param_spec_int ("host-port", + "Host port", + "The port of the host", + 0, G_MAXINT32, 631, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_IS_NETWORK_DEVICE, + g_param_spec_boolean ("is-network-device", + "Network device", + "Whether the new printer is a network device", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_WINDOW_ID, + g_param_spec_int ("window-id", + "WindowID", + "Window ID of parent window", + 0, G_MAXINT32, 631, + G_PARAM_READWRITE)); +} + +static void +pp_new_printer_init (PpNewPrinter *printer) +{ + printer->priv = G_TYPE_INSTANCE_GET_PRIVATE (printer, + PP_TYPE_NEW_PRINTER, + PpNewPrinterPrivate); + + printer->priv->unlink_ppd_file = FALSE; + printer->priv->cancellable = NULL; + printer->priv->res = NULL; +} + +PpNewPrinter * +pp_new_printer_new () +{ + return g_object_new (PP_TYPE_NEW_PRINTER, NULL); +} + +static void printer_configure_async (PpNewPrinter *new_printer); + +static void +_pp_new_printer_add_async_cb (gboolean success, + PpNewPrinter *printer) +{ + PpNewPrinterPrivate *priv = printer->priv; + + if (!success) + { + g_simple_async_result_set_error (priv->res, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Installation of the new printer failed."); + } + + g_simple_async_result_set_op_res_gboolean (priv->res, success); + g_simple_async_result_complete_in_idle (priv->res); +} + +static void +printer_add_real_async_cb (cups_dest_t *destination, + gpointer user_data) +{ + PpNewPrinter *printer = (PpNewPrinter *) user_data; + gboolean success = FALSE; + + if (destination) + { + success = TRUE; + cupsFreeDests (1, destination); + } + + if (success) + { + printer_configure_async (printer); + } + else + { + _pp_new_printer_add_async_cb (FALSE, printer); + } +} + +static void +printer_add_real_async_dbus_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinter *printer; + PpNewPrinterPrivate *priv; + GVariant *output; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + const gchar *ret_error; + + g_variant_get (output, "(&s)", &ret_error); + if (ret_error[0] != '\0') + { + g_warning ("%s", ret_error); + } + + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + } + + if (!error || + error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + { + printer = (PpNewPrinter *) user_data; + priv = printer->priv; + + get_named_dest_async (priv->name, + printer_add_real_async_cb, + printer); + } + + if (error) + g_error_free (error); +} + +static void +printer_add_real_async (PpNewPrinter *printer) +{ + PpNewPrinterPrivate *priv = printer->priv; + GDBusConnection *bus; + GError *error = NULL; + + if (!priv->ppd_name && !priv->ppd_file_name) + { + _pp_new_printer_add_async_cb (FALSE, printer); + return; + } + + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!bus) + { + g_warning ("Failed to get system bus: %s", error->message); + g_error_free (error); + _pp_new_printer_add_async_cb (FALSE, printer); + return; + } + + g_dbus_connection_call (bus, + MECHANISM_BUS, + "/", + MECHANISM_BUS, + priv->ppd_name ? "PrinterAdd" : "PrinterAddWithPpdFile", + g_variant_new ("(sssss)", + priv->name, + priv->device_uri, + priv->ppd_name ? priv->ppd_name : priv->ppd_file_name, + priv->info ? priv->info : "", + priv->location ? priv->location : ""), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, + printer_add_real_async_dbus_cb, + printer); +} + +static PPDName * +get_ppd_item_from_output (GVariant *output) +{ + GVariant *array; + PPDName *ppd_item = NULL; + gint j; + static const char * const match_levels[] = { + "exact-cmd", + "exact", + "close", + "generic", + "none"}; + + if (output) + { + g_variant_get (output, "(@a(ss))", &array); + if (array) + { + GVariantIter *iter; + GVariant *item; + gchar *driver; + gchar *match; + + for (j = 0; j < G_N_ELEMENTS (match_levels) && !ppd_item; j++) + { + g_variant_get (array, "a(ss)", &iter); + while ((item = g_variant_iter_next_value (iter)) && !ppd_item) + { + g_variant_get (item, "(ss)", &driver, &match); + if (g_str_equal (match, match_levels[j])) + { + ppd_item = g_new0 (PPDName, 1); + ppd_item->ppd_name = g_strdup (driver); + + if (g_strcmp0 (match, "exact-cmd") == 0) + ppd_item->ppd_match_level = PPD_EXACT_CMD_MATCH; + else if (g_strcmp0 (match, "exact") == 0) + ppd_item->ppd_match_level = PPD_EXACT_MATCH; + else if (g_strcmp0 (match, "close") == 0) + ppd_item->ppd_match_level = PPD_CLOSE_MATCH; + else if (g_strcmp0 (match, "generic") == 0) + ppd_item->ppd_match_level = PPD_GENERIC_MATCH; + else if (g_strcmp0 (match, "none") == 0) + ppd_item->ppd_match_level = PPD_NO_MATCH; + } + + g_free (driver); + g_free (match); + g_variant_unref (item); + } + } + + g_variant_unref (array); + } + } + + return ppd_item; +} + + +static void +printer_add_async_scb3 (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinter *printer = (PpNewPrinter *) user_data; + PpNewPrinterPrivate *priv = printer->priv; + GVariant *output; + PPDName *ppd_item = NULL; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + ppd_item = get_ppd_item_from_output (output); + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + } + + if ((!error || + error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) && + ppd_item && ppd_item->ppd_name) + { + priv->ppd_name = g_strdup (ppd_item->ppd_name); + printer_add_real_async (printer); + } + else + { + _pp_new_printer_add_async_cb (FALSE, printer); + } + + if (error) + { + g_error_free (error); + } + + if (ppd_item) + { + g_free (ppd_item->ppd_name); + g_free (ppd_item); + } +} + +static void +install_printer_drivers_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinterPrivate *priv; + PpNewPrinter *printer; + GVariant *output; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + } + + if (!error || + error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + { + GDBusConnection *bus; + GError *error = NULL; + + printer = (PpNewPrinter *) user_data; + priv = printer->priv; + + /* Try whether CUPS has a driver for the new printer */ + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (bus) + { + g_dbus_connection_call (bus, + SCP_BUS, + SCP_PATH, + SCP_IFACE, + "GetBestDrivers", + g_variant_new ("(sss)", + priv->device_id, + priv->make_and_model ? priv->make_and_model : "", + priv->device_uri ? priv->device_uri : ""), + G_VARIANT_TYPE ("(a(ss))"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + priv->cancellable, + printer_add_async_scb3, + printer); + } + else + { + g_warning ("Failed to get system bus: %s", error->message); + g_error_free (error); + _pp_new_printer_add_async_cb (FALSE, printer); + } + } + + if (error) + g_error_free (error); +} + +static void +printer_add_async_scb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpNewPrinter *printer = (PpNewPrinter *) user_data; + PpNewPrinterPrivate *priv = printer->priv; + GDBusConnection *bus; + GVariantBuilder array_builder; + GVariant *output; + PPDName *ppd_item = NULL; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + ppd_item = get_ppd_item_from_output (output); + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + if (!error || + error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + { + if (ppd_item == NULL || ppd_item->ppd_match_level < PPD_EXACT_MATCH) + { + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (bus) + { + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as")); + g_variant_builder_add (&array_builder, "s", priv->device_id); + + g_dbus_connection_call (bus, + PACKAGE_KIT_BUS, + PACKAGE_KIT_PATH, + PACKAGE_KIT_MODIFY_IFACE, + "InstallPrinterDrivers", + g_variant_new ("(uass)", + priv->window_id, + &array_builder, + "hide-finished"), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + NULL, + install_printer_drivers_cb, + printer); + } + else + { + g_warning ("Failed to get session bus: %s", error->message); + g_error_free (error); + _pp_new_printer_add_async_cb (FALSE, printer); + } + } + else if (ppd_item && ppd_item->ppd_name) + { + priv->ppd_name = g_strdup (ppd_item->ppd_name); + printer_add_real_async (printer); + } + else + { + _pp_new_printer_add_async_cb (FALSE, printer); + } + } + + if (ppd_item) + { + g_free (ppd_item->ppd_name); + g_free (ppd_item); + } +} + +static void +printer_add_async_scb4 (const gchar *ppd_filename, + gpointer user_data) +{ + PpNewPrinter *printer = (PpNewPrinter *) user_data; + PpNewPrinterPrivate *priv = printer->priv; + + priv->ppd_file_name = g_strdup (ppd_filename); + if (priv->ppd_file_name) + { + priv->unlink_ppd_file = TRUE; + printer_add_real_async (printer); + } + else + { + _pp_new_printer_add_async_cb (FALSE, printer); + } +} + +static GList * +glist_uniq (GList *list) +{ + GList *result = NULL; + GList *iter = NULL; + GList *tmp = NULL; + + for (iter = list; iter; iter = iter->next) + { + if (tmp == NULL || + g_strcmp0 ((gchar *) tmp->data, (gchar *) iter->data) != 0) + { + tmp = iter; + result = g_list_append (result, g_strdup (iter->data)); + } + } + + g_list_free_full (list, g_free); + + return result; +} + +typedef struct +{ + PpNewPrinter *new_printer; + GCancellable *cancellable; + gboolean set_accept_jobs_finished; + gboolean set_enabled_finished; + gboolean autoconfigure_finished; + gboolean set_media_size_finished; + gboolean install_missing_executables_finished; +} PCData; + +static void +printer_configure_async_finish (PCData *data) +{ + PpNewPrinterPrivate *priv = data->new_printer->priv; + + if (data->set_accept_jobs_finished && + data->set_enabled_finished && + (data->autoconfigure_finished || priv->is_network_device) && + data->set_media_size_finished && + data->install_missing_executables_finished) + { + _pp_new_printer_add_async_cb (TRUE, data->new_printer); + + if (data->cancellable) + g_object_unref (data->cancellable); + g_free (data); + } +} + +static void +pao_cb (gboolean success, + gpointer user_data) +{ + PCData *data = (PCData *) user_data; + + data->set_media_size_finished = TRUE; + printer_configure_async_finish (data); +} + +static void +printer_set_accepting_jobs_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *output; + PCData *data = (PCData *) user_data; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + data->set_accept_jobs_finished = TRUE; + printer_configure_async_finish (data); +} + +static void +printer_set_enabled_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *output; + PCData *data = (PCData *) user_data; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + data->set_enabled_finished = TRUE; + printer_configure_async_finish (data); +} + +typedef struct +{ + GList *executables; + GList *packages; + guint window_id; + gchar *ppd_file_name; + GCancellable *cancellable; + gpointer user_data; +} IMEData; + +static void +install_missing_executables_cb (IMEData *data) +{ + PCData *pc_data = (PCData *) data->user_data; + + pc_data->install_missing_executables_finished = TRUE; + printer_configure_async_finish (pc_data); + + if (data->ppd_file_name) + { + g_unlink (data->ppd_file_name); + g_clear_pointer (&data->ppd_file_name, g_free); + } + + if (data->executables) + { + g_list_free_full (data->executables, g_free); + data->executables = NULL; + } + + if (data->packages) + { + g_list_free_full (data->packages, g_free); + data->packages = NULL; + } + + if (data->cancellable) + g_clear_object (&data->cancellable); + + g_free (data); +} + +static void +install_package_names_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *output; + IMEData *data = (IMEData *) user_data; + GError *error = NULL; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + g_object_unref (source_object); + + if (output) + { + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + install_missing_executables_cb (data); +} + + +static void +search_files_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *output; + IMEData *data = (IMEData *) user_data; + GError *error = NULL; + GList *item; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + if (output) + { + gboolean installed; + gchar *package; + + g_variant_get (output, + "(bs)", + &installed, + &package); + + if (!installed) + data->packages = g_list_append (data->packages, g_strdup (package)); + g_variant_unref (output); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + if (data->executables) + { + item = data->executables; + g_dbus_connection_call (G_DBUS_CONNECTION (source_object), + PACKAGE_KIT_BUS, + PACKAGE_KIT_PATH, + PACKAGE_KIT_QUERY_IFACE, + "SearchFile", + g_variant_new ("(ss)", + (gchar *) item->data, + ""), + G_VARIANT_TYPE ("(bs)"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + data->cancellable, + search_files_cb, + data); + + data->executables = g_list_remove_link (data->executables, item); + g_list_free_full (item, g_free); + } + else + { + GVariantBuilder array_builder; + GList *pkg_iter; + + data->packages = g_list_sort (data->packages, (GCompareFunc) g_strcmp0); + data->packages = glist_uniq (data->packages); + + if (data->packages) + { + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as")); + + for (pkg_iter = data->packages; pkg_iter; pkg_iter = pkg_iter->next) + g_variant_builder_add (&array_builder, + "s", + (gchar *) pkg_iter->data); + + g_dbus_connection_call (G_DBUS_CONNECTION (source_object), + PACKAGE_KIT_BUS, + PACKAGE_KIT_PATH, + PACKAGE_KIT_MODIFY_IFACE, + "InstallPackageNames", + g_variant_new ("(uass)", + data->window_id, + &array_builder, + "hide-finished"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + data->cancellable, + install_package_names_cb, + data); + + g_list_free_full (data->packages, g_free); + data->packages = NULL; + } + else + { + g_object_unref (source_object); + install_missing_executables_cb (data); + } + } +} + +static void +get_missing_executables_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *output; + IMEData *data = (IMEData *) user_data; + GError *error = NULL; + GList *executables = NULL; + GList *item; + + output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), + res, + &error); + + if (output) + { + GVariant *array; + + g_variant_get (output, "(@as)", &array); + + if (array) + { + GVariantIter *iter; + GVariant *item; + gchar *executable; + + g_variant_get (array, "as", &iter); + while ((item = g_variant_iter_next_value (iter))) + { + g_variant_get (item, "s", &executable); + executables = g_list_append (executables, executable); + g_variant_unref (item); + } + + g_variant_unref (array); + } + + g_variant_unref (output); + } + else if (error->domain == G_DBUS_ERROR && + (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN || + error->code == G_DBUS_ERROR_UNKNOWN_METHOD)) + { + g_warning ("Install system-config-printer which provides \ +DBus method \"MissingExecutables\" to find missing executables and filters."); + g_error_free (error); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + g_warning ("%s", error->message); + g_error_free (error); + } + + executables = g_list_sort (executables, (GCompareFunc) g_strcmp0); + executables = glist_uniq (executables); + + if (executables) + { + data->executables = executables; + + item = data->executables; + g_dbus_connection_call (g_object_ref (source_object), + PACKAGE_KIT_BUS, + PACKAGE_KIT_PATH, + PACKAGE_KIT_QUERY_IFACE, + "SearchFile", + g_variant_new ("(ss)", + (gchar *) item->data, + ""), + G_VARIANT_TYPE ("(bs)"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + data->cancellable, + search_files_cb, + data); + + data->executables = g_list_remove_link (data->executables, item); + g_list_free_full (item, g_free); + } + else + { + g_object_unref (source_object); + install_missing_executables_cb (data); + } + + if (data->ppd_file_name) + { + g_unlink (data->ppd_file_name); + g_clear_pointer (&data->ppd_file_name, g_free); + } +} + +static void +printer_get_ppd_cb (const gchar *ppd_filename, + gpointer user_data) +{ + GDBusConnection *bus; + IMEData *data = (IMEData *) user_data; + GError *error = NULL; + + data->ppd_file_name = g_strdup (ppd_filename); + if (data->ppd_file_name) + { + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (!bus) + { + g_warning ("%s", error->message); + g_error_free (error); + } + else + { + g_dbus_connection_call (bus, + SCP_BUS, + SCP_PATH, + SCP_IFACE, + "MissingExecutables", + g_variant_new ("(s)", data->ppd_file_name), + G_VARIANT_TYPE ("(as)"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + data->cancellable, + get_missing_executables_cb, + data); + return; + } + } + + install_missing_executables_cb (data); +} + +static void +pp_maintenance_command_execute_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PpMaintenanceCommand *command = (PpMaintenanceCommand *) source_object; + GError *error = NULL; + PCData *data; + gboolean result; + + result = pp_maintenance_command_execute_finish (command, res, &error); + g_object_unref (source_object); + + if (result) + { + data = (PCData *) user_data; + + data->autoconfigure_finished = TRUE; + printer_configure_async_finish (data); + } + else + { + if (error->domain != G_IO_ERROR || + error->code != G_IO_ERROR_CANCELLED) + { + data = (PCData *) user_data; + + g_warning ("%s", error->message); + + data->autoconfigure_finished = TRUE; + printer_configure_async_finish (data); + } + + g_error_free (error); + } +} + +static void +printer_configure_async (PpNewPrinter *new_printer) +{ + PpNewPrinterPrivate *priv = new_printer->priv; + GDBusConnection *bus; + PCData *data; + IMEData *ime_data; + gchar **values; + GError *error = NULL; + + data = g_new0 (PCData, 1); + data->new_printer = new_printer; + data->set_accept_jobs_finished = FALSE; + data->set_enabled_finished = FALSE; + data->autoconfigure_finished = FALSE; + data->set_media_size_finished = FALSE; + data->install_missing_executables_finished = FALSE; + + /* Enable printer and make it accept jobs */ + if (priv->name) + { + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (bus) + { + g_dbus_connection_call (bus, + MECHANISM_BUS, + "/", + MECHANISM_BUS, + "PrinterSetAcceptJobs", + g_variant_new ("(sbs)", + priv->name, + TRUE, + ""), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + printer_set_accepting_jobs_cb, + data); + + g_dbus_connection_call (g_object_ref (bus), + MECHANISM_BUS, + "/", + MECHANISM_BUS, + "PrinterSetEnabled", + g_variant_new ("(sb)", + priv->name, + TRUE), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + printer_set_enabled_cb, + data); + } + else + { + g_warning ("Failed to get system bus: %s", error->message); + g_error_free (error); + data->set_accept_jobs_finished = TRUE; + data->set_enabled_finished = TRUE; + } + } + else + { + data->set_accept_jobs_finished = TRUE; + data->set_enabled_finished = TRUE; + } + + /* Run autoconfiguration of printer */ + if (!priv->is_network_device) + { + PpMaintenanceCommand *command; + command = pp_maintenance_command_new (priv->name, + "autoconfigure", + /* Translators: Name of job which makes printer to autoconfigure itself */ + _("Automatic configuration")); + + pp_maintenance_command_execute_async (command, + NULL, + pp_maintenance_command_execute_cb, + data); + } + + /* Set media size for printer */ + values = g_new0 (gchar *, 2); + values[0] = g_strdup (get_paper_size_from_locale ()); + + printer_add_option_async (priv->name, "media", values, TRUE, NULL, pao_cb, data); + + g_strfreev (values); + + /* Install missing executables for printer */ + ime_data = g_new0 (IMEData, 1); + ime_data->window_id = priv->window_id; + if (data->cancellable) + ime_data->cancellable = g_object_ref (data->cancellable); + ime_data->user_data = data; + + printer_get_ppd_async (priv->name, + NULL, + 0, + printer_get_ppd_cb, + ime_data); +} + +static void +_pp_new_printer_add_async (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + PpNewPrinter *printer = PP_NEW_PRINTER (object); + PpNewPrinterPrivate *priv = printer->priv; + + priv->res = g_object_ref (res); + priv->cancellable = g_object_ref (cancellable); + + if (priv->ppd_name || priv->ppd_file_name) + { + /* We have everything we need */ + printer_add_real_async (printer); + } + else if (priv->device_id) + { + GDBusConnection *bus; + GError *error = NULL; + + /* Try whether CUPS has a driver for the new printer */ + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (bus) + { + g_dbus_connection_call (bus, + SCP_BUS, + SCP_PATH, + SCP_IFACE, + "GetBestDrivers", + g_variant_new ("(sss)", + priv->device_id, + priv->make_and_model ? priv->make_and_model : "", + priv->device_uri ? priv->device_uri : ""), + G_VARIANT_TYPE ("(a(ss))"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_LONG, + cancellable, + printer_add_async_scb, + printer); + } + else + { + g_warning ("Failed to get system bus: %s", error->message); + g_error_free (error); + _pp_new_printer_add_async_cb (FALSE, printer); + } + } + else if (priv->original_name && priv->host_name) + { + /* Try to get PPD from remote CUPS */ + printer_get_ppd_async (priv->original_name, + priv->host_name, + priv->host_port, + printer_add_async_scb4, + printer); + } + else + { + _pp_new_printer_add_async_cb (FALSE, printer); + } +} + +void +pp_new_printer_add_async (PpNewPrinter *printer, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + res = g_simple_async_result_new (G_OBJECT (printer), callback, user_data, pp_new_printer_add_async); + + g_simple_async_result_set_check_cancellable (res, cancellable); + _pp_new_printer_add_async (res, G_OBJECT (printer), cancellable); + + g_object_unref (res); +} + +gboolean +pp_new_printer_add_finish (PpNewPrinter *printer, + GAsyncResult *res, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_new_printer_add_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + return g_simple_async_result_get_op_res_gboolean (simple); +} diff -Nru gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/background.ui gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/background.ui --- gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/background.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/background.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,177 @@ + + + + + True + False + 10 + 12 + 6 + 6 + 6 + 6 + + + True + False + 6 + + + True + False + 12 + 0 + none + + + False + True + True + True + center + + + 417 + 250 + True + False + center + 6 + 6 + 6 + 6 + True + True + + + + + + + True + True + 0 + + + + + True + False + 12 + + + True + False + center + 2 + + + True + False + slideshow-symbolic + + + False + True + 0 + + + + + True + False + + + + False + True + 1 + + + + + True + False + 0 + Changes throughout the day + + + False + True + 1 + + + + + True + True + 0 + + + + + False + True + 2 + + + + + True + True + 0 + + + + + + + + + + + + + + + + + + + + + + + Tile + 1 + + + Zoom + 5 + + + Center + 2 + + + Scale + 3 + + + Fill + 4 + + + Span + 6 + + + + + vertical + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/cc-background-panel.c gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/cc-background-panel.c --- gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/cc-background-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-background-lock-screen.patch/panels/background/cc-background-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,747 @@ +/* + * Copyright (C) 2010 Intel, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Thomas Wood + * + */ + +#include + +#include +#include +#include +#include + +#include + +#include "cc-background-panel.h" + +#include "cc-background-item.h" +#include "cc-background-xml.h" + +#include "cc-background-chooser-dialog.h" + +#include "bg-pictures-source.h" + +#define WP_PATH_ID "org.gnome.desktop.background" +#define WP_URI_KEY "picture-uri" +#define WP_OPTIONS_KEY "picture-options" +#define WP_SHADING_KEY "color-shading-type" +#define WP_PCOLOR_KEY "primary-color" +#define WP_SCOLOR_KEY "secondary-color" + +CC_PANEL_REGISTER (CcBackgroundPanel, cc_background_panel) + +#define BACKGROUND_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_BACKGROUND_PANEL, CcBackgroundPanelPrivate)) + +struct _CcBackgroundPanelPrivate +{ + GtkBuilder *builder; + GDBusConnection *connection; + + GSettings *settings; + + GnomeDesktopThumbnailFactory *thumb_factory; + + CcBackgroundItem *current_background; + + GCancellable *copy_cancellable; + GCancellable *capture_cancellable; + + GtkWidget *spinner; + + GdkPixbuf *display_screenshot; + char *screenshot_path; +}; + +#define WID(y) (GtkWidget *) gtk_builder_get_object (priv->builder, y) + +static const char * +cc_background_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/look-background"; +} + +static void +cc_background_panel_dispose (GObject *object) +{ + CcBackgroundPanelPrivate *priv = CC_BACKGROUND_PANEL (object)->priv; + + g_clear_object (&priv->builder); + + /* destroying the builder object will also destroy the spinner */ + priv->spinner = NULL; + + g_clear_object (&priv->settings); + + if (priv->copy_cancellable) + { + /* cancel any copy operation */ + g_cancellable_cancel (priv->copy_cancellable); + + g_object_unref (priv->copy_cancellable); + priv->copy_cancellable = NULL; + } + + if (priv->capture_cancellable) + { + /* cancel screenshot operations */ + g_cancellable_cancel (priv->capture_cancellable); + + g_object_unref (priv->capture_cancellable); + priv->capture_cancellable = NULL; + } + + g_clear_object (&priv->thumb_factory); + g_clear_object (&priv->display_screenshot); + + g_free (priv->screenshot_path); + priv->screenshot_path = NULL; + + g_clear_object (&priv->connection); + + G_OBJECT_CLASS (cc_background_panel_parent_class)->dispose (object); +} + +static void +cc_background_panel_finalize (GObject *object) +{ + CcBackgroundPanelPrivate *priv = CC_BACKGROUND_PANEL (object)->priv; + + g_clear_object (&priv->current_background); + + G_OBJECT_CLASS (cc_background_panel_parent_class)->finalize (object); +} + +static void +cc_background_panel_class_init (CcBackgroundPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcBackgroundPanelPrivate)); + + panel_class->get_help_uri = cc_background_panel_get_help_uri; + + object_class->dispose = cc_background_panel_dispose; + object_class->finalize = cc_background_panel_finalize; +} + +static void +update_preview (CcBackgroundPanelPrivate *priv, + CcBackgroundItem *item) +{ + gboolean changes_with_time; + + if (item && priv->current_background) + { + g_object_unref (priv->current_background); + priv->current_background = cc_background_item_copy (item); + cc_background_item_load (priv->current_background, NULL); + } + + changes_with_time = FALSE; + + if (priv->current_background) + { + changes_with_time = cc_background_item_changes_with_time (priv->current_background); + } + + gtk_widget_set_visible (WID ("slide_image"), changes_with_time); + gtk_widget_set_visible (WID ("slide-label"), changes_with_time); + + gtk_widget_queue_draw (WID ("background-desktop-drawingarea")); +} + +static char * +get_save_path (void) +{ + return g_build_filename (g_get_user_config_dir (), + "gnome-control-center", + "backgrounds", + "last-edited.xml", + NULL); +} + +static void +update_display_preview (CcBackgroundPanel *panel) +{ + CcBackgroundPanelPrivate *priv = panel->priv; + GtkWidget *widget; + GtkAllocation allocation; + const gint preview_width = 416; + const gint preview_height = 248; + GdkPixbuf *pixbuf; + GIcon *icon; + cairo_t *cr; + + widget = WID ("background-desktop-drawingarea"); + gtk_widget_get_allocation (widget, &allocation); + + if (!priv->current_background) + return; + + icon = cc_background_item_get_frame_thumbnail (priv->current_background, + priv->thumb_factory, + preview_width, + preview_height, + -2, TRUE); + pixbuf = GDK_PIXBUF (icon); + + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + gdk_cairo_set_source_pixbuf (cr, + pixbuf, + 0, 0); + cairo_paint (cr); + g_object_unref (pixbuf); + + pixbuf = NULL; + if (panel->priv->display_screenshot != NULL) + pixbuf = gdk_pixbuf_scale_simple (panel->priv->display_screenshot, + preview_width, + preview_height, + GDK_INTERP_BILINEAR); + + if (pixbuf) + { + gdk_cairo_set_source_pixbuf (cr, + pixbuf, + 0, 0); + cairo_paint (cr); + } + + cairo_destroy (cr); +} + +static void +on_screenshot_finished (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CcBackgroundPanel *panel = user_data; + CcBackgroundPanelPrivate *priv = panel->priv; + GError *error; + GdkRectangle rect; + GdkRectangle workarea_rect; + GtkWidget *widget; + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + cairo_t *cr; + int width; + int height; + int primary; + + error = NULL; + g_dbus_connection_call_finish (panel->priv->connection, + res, + &error); + + if (error != NULL) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + return; + } + g_debug ("Unable to get screenshot: %s", + error->message); + g_error_free (error); + /* fallback? */ + goto out; + } + + pixbuf = gdk_pixbuf_new_from_file (panel->priv->screenshot_path, &error); + if (error != NULL) + { + g_debug ("Unable to use GNOME Shell's builtin screenshot interface: %s", + error->message); + g_error_free (error); + goto out; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + cr = cairo_create (surface); + gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + cairo_paint (cr); + g_object_unref (pixbuf); + + /* clear the workarea */ + widget = WID ("background-desktop-drawingarea"); + primary = gdk_screen_get_primary_monitor (gtk_widget_get_screen (widget)); + gdk_screen_get_monitor_geometry (gtk_widget_get_screen (widget), primary, &rect); + gdk_screen_get_monitor_workarea (gtk_widget_get_screen (widget), primary, &workarea_rect); + + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_rectangle (cr, workarea_rect.x - rect.x, workarea_rect.y - rect.y, workarea_rect.width, workarea_rect.height); + cairo_fill (cr); + cairo_restore (cr); + + g_clear_object (&panel->priv->display_screenshot); + panel->priv->display_screenshot = gdk_pixbuf_get_from_surface (surface, + 0, 0, + width, + height); + /* remove the temporary file created by the shell */ + g_unlink (panel->priv->screenshot_path); + g_free (priv->screenshot_path); + priv->screenshot_path = NULL; + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + out: + update_display_preview (panel); +} + +static void +get_screenshot_async (CcBackgroundPanel *panel, + GdkRectangle *rectangle) +{ + gchar *path, *tmpname; + const gchar *method_name; + GVariant *method_params; + + g_debug ("Trying to capture rectangle %dx%d (at %d,%d)", + rectangle->width, rectangle->height, rectangle->x, rectangle->y); + + path = g_build_filename (g_get_user_cache_dir (), "gnome-control-center", NULL); + g_mkdir_with_parents (path, 0700); + + tmpname = g_strdup_printf ("scr-%d.png", g_random_int ()); + g_free (panel->priv->screenshot_path); + panel->priv->screenshot_path = g_build_filename (path, tmpname, NULL); + g_free (path); + g_free (tmpname); + + method_name = "ScreenshotArea"; + method_params = g_variant_new ("(iiiibs)", + rectangle->x, rectangle->y, + rectangle->width, rectangle->height, + FALSE, /* flash */ + panel->priv->screenshot_path); + + g_dbus_connection_call (panel->priv->connection, + "org.gnome.Shell", + "/org/gnome/Shell", + "org.gnome.Shell", + method_name, + method_params, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + panel->priv->capture_cancellable, + on_screenshot_finished, + panel); +} + +static gboolean +on_preview_draw (GtkWidget *widget, + cairo_t *cr, + CcBackgroundPanel *panel) +{ + /* we have another shot in flight or an existing cache */ + if (panel->priv->display_screenshot == NULL + && panel->priv->screenshot_path == NULL) + { + GdkRectangle rect; + int primary; + + primary = gdk_screen_get_primary_monitor (gtk_widget_get_screen (widget)); + gdk_screen_get_monitor_geometry (gtk_widget_get_screen (widget), primary, &rect); + get_screenshot_async (panel, &rect); + } + else + update_display_preview (panel); + + return TRUE; +} + +static void +reload_current_bg (CcBackgroundPanel *self) +{ + CcBackgroundPanelPrivate *priv; + CcBackgroundItem *saved, *configured; + gchar *uri, *pcolor, *scolor; + + priv = self->priv; + + /* Load the saved configuration */ + uri = get_save_path (); + saved = cc_background_xml_get_item (uri); + g_free (uri); + + /* initalise the current background information from settings */ + uri = g_settings_get_string (priv->settings, WP_URI_KEY); + if (uri && *uri == '\0') + { + g_free (uri); + uri = NULL; + } + else + { + GFile *file; + + file = g_file_new_for_commandline_arg (uri); + g_object_unref (file); + } + configured = cc_background_item_new (uri); + g_free (uri); + + pcolor = g_settings_get_string (priv->settings, WP_PCOLOR_KEY); + scolor = g_settings_get_string (priv->settings, WP_SCOLOR_KEY); + g_object_set (G_OBJECT (configured), + "name", _("Current background"), + "placement", g_settings_get_enum (priv->settings, WP_OPTIONS_KEY), + "shading", g_settings_get_enum (priv->settings, WP_SHADING_KEY), + "primary-color", pcolor, + "secondary-color", scolor, + NULL); + g_free (pcolor); + g_free (scolor); + + if (saved != NULL && cc_background_item_compare (saved, configured)) + { + CcBackgroundItemFlags flags; + flags = cc_background_item_get_flags (saved); + /* Special case for colours */ + if (cc_background_item_get_placement (saved) == G_DESKTOP_BACKGROUND_STYLE_NONE) + flags &=~ (CC_BACKGROUND_ITEM_HAS_PCOLOR | CC_BACKGROUND_ITEM_HAS_SCOLOR); + g_object_set (G_OBJECT (configured), + "name", cc_background_item_get_name (saved), + "flags", flags, + "source-url", cc_background_item_get_source_url (saved), + "source-xml", cc_background_item_get_source_xml (saved), + NULL); + } + if (saved != NULL) + g_object_unref (saved); + + g_clear_object (&priv->current_background); + priv->current_background = configured; + cc_background_item_load (priv->current_background, NULL); +} + +static gboolean +create_save_dir (void) +{ + char *path; + + path = g_build_filename (g_get_user_config_dir (), + "gnome-control-center", + "backgrounds", + NULL); + if (g_mkdir_with_parents (path, 0755) < 0) + { + g_warning ("Failed to create directory '%s'", path); + g_free (path); + return FALSE; + } + g_free (path); + return TRUE; +} + +static void +copy_finished_cb (GObject *source_object, + GAsyncResult *result, + gpointer pointer) +{ + GError *err = NULL; + CcBackgroundPanel *panel = (CcBackgroundPanel *) pointer; + CcBackgroundPanelPrivate *priv = panel->priv; + CcBackgroundItem *item; + + if (!g_file_copy_finish (G_FILE (source_object), result, &err)) + { + if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (err); + return; + } + g_warning ("Failed to copy image to cache location: %s", err->message); + g_error_free (err); + } + item = g_object_get_data (source_object, "item"); + + g_settings_apply (priv->settings); + + /* the panel may have been destroyed before the callback is run, so be sure + * to check the widgets are not NULL */ + + if (priv->spinner) + { + gtk_widget_destroy (GTK_WIDGET (priv->spinner)); + priv->spinner = NULL; + } + + if (priv->current_background) + cc_background_item_load (priv->current_background, NULL); + + if (priv->builder) + { + char *filename; + + update_preview (priv, item); + + /* Save the source XML if there is one */ + filename = get_save_path (); + if (create_save_dir ()) + cc_background_xml_save (priv->current_background, filename); + } + + /* remove the reference taken when the copy was set up */ + g_object_unref (panel); +} + +static void +set_background (CcBackgroundPanel *panel, + CcBackgroundItem *item) +{ + CcBackgroundPanelPrivate *priv = panel->priv; + GDesktopBackgroundStyle style; + gboolean save_settings = TRUE; + const char *uri; + CcBackgroundItemFlags flags; + char *filename; + + if (item == NULL) + return; + + uri = cc_background_item_get_uri (item); + flags = cc_background_item_get_flags (item); + + if ((flags & CC_BACKGROUND_ITEM_HAS_URI) && uri == NULL) + { + g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE); + g_settings_set_string (priv->settings, WP_URI_KEY, ""); + } + else if (cc_background_item_get_source_url (item) != NULL && + cc_background_item_get_needs_download (item)) + { + GFile *source, *dest; + char *cache_path, *basename, *dest_path, *display_name, *dest_uri; + GdkPixbuf *pixbuf; + + cache_path = bg_pictures_source_get_cache_path (); + if (g_mkdir_with_parents (cache_path, 0755) < 0) + { + g_warning ("Failed to create directory '%s'", cache_path); + g_free (cache_path); + return; + } + g_free (cache_path); + + dest_path = bg_pictures_source_get_unique_path (cc_background_item_get_source_url (item)); + dest = g_file_new_for_path (dest_path); + g_free (dest_path); + source = g_file_new_for_uri (cc_background_item_get_source_url (item)); + basename = g_file_get_basename (source); + display_name = g_filename_display_name (basename); + dest_path = g_file_get_path (dest); + g_free (basename); + + /* create a blank image to use until the source image is ready */ + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1); + gdk_pixbuf_fill (pixbuf, 0x00000000); + gdk_pixbuf_save (pixbuf, dest_path, "png", NULL, NULL); + g_object_unref (pixbuf); + g_free (dest_path); + + if (priv->copy_cancellable) + { + g_cancellable_cancel (priv->copy_cancellable); + g_cancellable_reset (priv->copy_cancellable); + } + + if (priv->spinner) + { + gtk_widget_destroy (GTK_WIDGET (priv->spinner)); + priv->spinner = NULL; + } + + /* create a spinner while the file downloads */ + priv->spinner = gtk_spinner_new (); + gtk_spinner_start (GTK_SPINNER (priv->spinner)); + gtk_box_pack_start (GTK_BOX (WID ("bottom-hbox")), priv->spinner, FALSE, + FALSE, 6); + gtk_widget_show (priv->spinner); + + /* reference the panel in case it is removed before the copy is + * finished */ + g_object_ref (panel); + g_object_set_data_full (G_OBJECT (source), "item", g_object_ref (item), g_object_unref); + g_file_copy_async (source, dest, G_FILE_COPY_OVERWRITE, + G_PRIORITY_DEFAULT, priv->copy_cancellable, + NULL, NULL, + copy_finished_cb, panel); + g_object_unref (source); + dest_uri = g_file_get_uri (dest); + g_object_unref (dest); + + g_settings_set_string (priv->settings, WP_URI_KEY, dest_uri); + g_object_set (G_OBJECT (item), + "uri", dest_uri, + "needs-download", FALSE, + "name", display_name, + NULL); + g_free (display_name); + g_free (dest_uri); + + /* delay the updated drawing of the preview until the copy finishes */ + save_settings = FALSE; + } + else + { + g_settings_set_string (priv->settings, WP_URI_KEY, uri); + } + + /* Also set the placement if we have a URI and the previous value was none */ + if (flags & CC_BACKGROUND_ITEM_HAS_PLACEMENT) + { + g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); + } + else if (uri != NULL) + { + style = g_settings_get_enum (priv->settings, WP_OPTIONS_KEY); + if (style == G_DESKTOP_BACKGROUND_STYLE_NONE) + g_settings_set_enum (priv->settings, WP_OPTIONS_KEY, cc_background_item_get_placement (item)); + } + + if (flags & CC_BACKGROUND_ITEM_HAS_SHADING) + g_settings_set_enum (priv->settings, WP_SHADING_KEY, cc_background_item_get_shading (item)); + + g_settings_set_string (priv->settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item)); + g_settings_set_string (priv->settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item)); + + /* update the preview information */ + if (save_settings != FALSE) + { + /* Apply all changes */ + g_settings_apply (priv->settings); + + /* Save the source XML if there is one */ + filename = get_save_path (); + if (create_save_dir ()) + cc_background_xml_save (priv->current_background, filename); + } +} + +static void +on_chooser_dialog_response (GtkDialog *dialog, + int response_id, + CcBackgroundPanel *self) +{ + if (response_id == GTK_RESPONSE_OK) + { + CcBackgroundItem *item; + + item = cc_background_chooser_dialog_get_item (CC_BACKGROUND_CHOOSER_DIALOG (dialog)); + if (item != NULL) + { + set_background (self, item); + g_object_unref (item); + } + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +on_background_button_clicked (GtkButton *button, + CcBackgroundPanel *self) +{ + CcBackgroundPanelPrivate *priv = self->priv; + GtkWidget *dialog; + + dialog = cc_background_chooser_dialog_new (); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gtk_widget_get_toplevel (WID ("background-panel")))); + gtk_widget_show (dialog); + g_signal_connect (dialog, "response", G_CALLBACK (on_chooser_dialog_response), self); +} + +static void +on_settings_changed (GSettings *settings, + gchar *key, + CcBackgroundPanel *self) +{ + reload_current_bg (self); + update_preview (self->priv, NULL); +} + +static void +cc_background_panel_init (CcBackgroundPanel *self) +{ + CcBackgroundPanelPrivate *priv; + gchar *objects[] = {"background-panel", NULL }; + GError *err = NULL; + GtkWidget *widget; + + priv = self->priv = BACKGROUND_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + priv->connection = g_application_get_dbus_connection (g_application_get_default ()); + + gtk_builder_add_objects_from_file (priv->builder, + UIDIR"/background.ui", + objects, &err); + + if (err) + { + g_warning ("Could not load ui: %s", err->message); + g_error_free (err); + return; + } + + priv->settings = g_settings_new (WP_PATH_ID); + g_settings_delay (priv->settings); + + /* add the top level widget */ + widget = WID ("background-panel"); + + gtk_container_add (GTK_CONTAINER (self), widget); + gtk_widget_show_all (GTK_WIDGET (self)); + + /* setup preview area */ + widget = WID ("background-desktop-drawingarea"); + g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), + self); + + priv->copy_cancellable = g_cancellable_new (); + priv->capture_cancellable = g_cancellable_new (); + + priv->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); + + reload_current_bg (self); + update_preview (priv, NULL); + + g_signal_connect (priv->settings, "changed", G_CALLBACK (on_settings_changed), self); + + widget = WID ("background-set-button"); + g_signal_connect (widget, "clicked", G_CALLBACK (on_background_button_clicked), self); +} + +void +cc_background_panel_register (GIOModule *module) +{ + cc_background_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_BACKGROUND_PANEL, + "background", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/git-background-remove-unused-widget.patch/panels/background/background.ui gnome-control-center-3.6.3/.pc/git-background-remove-unused-widget.patch/panels/background/background.ui --- gnome-control-center-3.6.3/.pc/git-background-remove-unused-widget.patch/panels/background/background.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-background-remove-unused-widget.patch/panels/background/background.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,205 @@ + + + + + True + False + 10 + 12 + + + True + False + 6 + + + True + False + 12 + 0 + none + + + False + True + True + True + center + + + True + False + True + 18 + + + 417 + 250 + True + False + center + 6 + 6 + 6 + 6 + True + True + + + True + True + 0 + + + + + False + True + center + 6 + 6 + 6 + True + True + + + True + True + 1 + + + + + + + + + True + True + 0 + + + + + True + False + 12 + + + True + False + center + 2 + + + True + False + slideshow-symbolic + + + False + True + 0 + + + + + True + False + 0 + Changes throughout the day + + + False + True + 1 + + + + + True + False + + + + False + True + 1 + + + + + True + True + 0 + + + + + False + True + 2 + + + + + True + True + 0 + + + + + + + + + + + + + + + + + + + + + + + Tile + 1 + + + Zoom + 5 + + + Center + 2 + + + Scale + 3 + + + Fill + 4 + + + Span + 6 + + + + + vertical + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/git_drop_ibus_engine_whitelist.patch/panels/region/gnome-region-panel-input.c gnome-control-center-3.6.3/.pc/git_drop_ibus_engine_whitelist.patch/panels/region/gnome-region-panel-input.c --- gnome-control-center-3.6.3/.pc/git_drop_ibus_engine_whitelist.patch/panels/region/gnome-region-panel-input.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_drop_ibus_engine_whitelist.patch/panels/region/gnome-region-panel-input.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1580 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by: Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#include +#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#ifdef HAVE_IBUS +#include +#endif + +#include "gdm-languages.h" +#include "gnome-region-panel-input.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s)) + +#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" + +#define KEY_CURRENT_INPUT_SOURCE "current" +#define KEY_INPUT_SOURCES "sources" + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +enum { + NAME_COLUMN, + TYPE_COLUMN, + ID_COLUMN, + SETUP_COLUMN, + N_COLUMNS +}; + +static GSettings *input_sources_settings = NULL; +static GnomeXkbInfo *xkb_info = NULL; +static GtkWidget *input_chooser = NULL; /* weak pointer */ + +#ifdef HAVE_IBUS +static IBusBus *ibus = NULL; +static GHashTable *ibus_engines = NULL; +static GCancellable *ibus_cancellable = NULL; +static guint shell_name_watch_id = 0; + +static const gchar *supported_ibus_engines[] = { + /* Simplified Chinese */ + "pinyin", + "bopomofo", + "wubi", + "erbi", + /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ + "libpinyin", + "libbopomofo", + + /* Traditional Chinese */ + /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ + "chewing", + "cangjie5", + "cangjie3", + "quick5", + "quick3", + "stroke5", + + /* Japanese */ + "anthy", + "mozc-jp", + "skk", + + /* Korean */ + "hangul", + + /* Thai */ + "m17n:th:kesmanee", + "m17n:th:pattachote", + "m17n:th:tis820", + + /* Vietnamese */ + "m17n:vi:tcvn", + "m17n:vi:telex", + "m17n:vi:viqr", + "m17n:vi:vni", + "Unikey", + + /* Sinhala */ + "m17n:si:wijesekera", + "m17n:si:phonetic-dynamic", + "m17n:si:trans", + "sayura", + + /* Indic */ + /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ + + /* Assamese */ + "m17n:as:phonetic", + "m17n:as:inscript", + "m17n:as:itrans", + + /* Bengali */ + "m17n:bn:inscript", + "m17n:bn:itrans", + "m17n:bn:probhat", + + /* Gujarati */ + "m17n:gu:inscript", + "m17n:gu:itrans", + "m17n:gu:phonetic", + + /* Hindi */ + "m17n:hi:inscript", + "m17n:hi:itrans", + "m17n:hi:phonetic", + "m17n:hi:remington", + "m17n:hi:typewriter", + "m17n:hi:vedmata", + + /* Kannada */ + "m17n:kn:kgp", + "m17n:kn:inscript", + "m17n:kn:itrans", + + /* Kashmiri */ + "m17n:ks:inscript", + + /* Maithili */ + "m17n:mai:inscript", + + /* Malayalam */ + "m17n:ml:inscript", + "m17n:ml:itrans", + "m17n:ml:mozhi", + "m17n:ml:swanalekha", + + /* Marathi */ + "m17n:mr:inscript", + "m17n:mr:itrans", + "m17n:mr:phonetic", + + /* Nepali */ + "m17n:ne:rom", + "m17n:ne:trad", + + /* Oriya */ + "m17n:or:inscript", + "m17n:or:itrans", + "m17n:or:phonetic", + + /* Punjabi */ + "m17n:pa:inscript", + "m17n:pa:itrans", + "m17n:pa:phonetic", + "m17n:pa:jhelum", + + /* Sanskrit */ + "m17n:sa:harvard-kyoto", + + /* Sindhi */ + "m17n:sd:inscript", + + /* Tamil */ + "m17n:ta:tamil99", + "m17n:ta:inscript", + "m17n:ta:itrans", + "m17n:ta:phonetic", + "m17n:ta:lk-renganathan", + "m17n:ta:vutam", + "m17n:ta:typewriter", + + /* Telugu */ + "m17n:te:inscript", + "m17n:te:apple", + "m17n:te:pothana", + "m17n:te:rts", + + /* Urdu */ + "m17n:ur:phonetic", + + /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ + "m17n:as:inscript2", + "m17n:bn:inscript2", + "m17n:brx:inscript2-deva", + "m17n:doi:inscript2-deva", + "m17n:gu:inscript2", + "m17n:hi:inscript2", + "m17n:kn:inscript2", + "m17n:kok:inscript2-deva", + "m17n:mai:inscript2", + "m17n:ml:inscript2", + "m17n:mni:inscript2-beng", + "m17n:mni:inscript2-mtei", + "m17n:mr:inscript2", + "m17n:ne:inscript2-deva", + "m17n:or:inscript2", + "m17n:pa:inscript2-guru", + "m17n:sa:inscript2", + "m17n:sat:inscript2-deva", + "m17n:sat:inscript2-olck", + "m17n:sd:inscript2-deva", + "m17n:ta:inscript2", + "m17n:te:inscript2", + + /* No corresponding XKB map available for the languages */ + + /* Chinese Yi */ + "m17n:ii:phonetic", + + /* Tai-Viet */ + "m17n:tai:sonla", + + /* Kazakh in Arabic script */ + "m17n:kk:arabic", + + /* Yiddish */ + "m17n:yi:yivo", + + /* Canadian Aboriginal languages */ + "m17n:ath:phonetic", + "m17n:bla:phonetic", + "m17n:cr:western", + "m17n:iu:phonetic", + "m17n:nsk:phonetic", + "m17n:oj:phonetic", + + /* Non-trivial engines, like transliteration-based instead of + keymap-based. Confirmation needed that the engines below are + actually used by local language users. */ + + /* Tibetan */ + "m17n:bo:ewts", + "m17n:bo:tcrc", + "m17n:bo:wylie", + + /* Esperanto */ + "m17n:eo:h-f", + "m17n:eo:h", + "m17n:eo:plena", + "m17n:eo:q", + "m17n:eo:vi", + "m17n:eo:x", + + /* Amharic */ + "m17n:am:sera", + + /* Russian */ + "m17n:ru:translit", + + /* Classical Greek */ + "m17n:grc:mizuochi", + + /* Lao */ + "m17n:lo:lrt", + + /* Postfix modifier input methods */ + "m17n:da:post", + "m17n:sv:post", + NULL +}; +#endif /* HAVE_IBUS */ + +static void populate_model (GtkListStore *store, + GtkListStore *active_sources_store); +static GtkWidget *input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources); +static gboolean input_chooser_get_selected (GtkWidget *chooser, + GtkTreeModel **model, + GtkTreeIter *iter); +static GtkTreeModel *tree_view_get_actual_model (GtkTreeView *tv); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +#ifdef HAVE_IBUS +static void +clear_ibus (void) +{ + if (shell_name_watch_id > 0) + { + g_bus_unwatch_name (shell_name_watch_id); + shell_name_watch_id = 0; + } + g_cancellable_cancel (ibus_cancellable); + g_clear_object (&ibus_cancellable); + g_clear_pointer (&ibus_engines, g_hash_table_destroy); + g_clear_object (&ibus); +} + +static gchar * +engine_get_display_name (IBusEngineDesc *engine_desc) +{ + const gchar *name; + const gchar *language_code; + const gchar *language; + gchar *display_name; + + name = ibus_engine_desc_get_longname (engine_desc); + language_code = ibus_engine_desc_get_language (engine_desc); + language = ibus_get_language_name (language_code); + + display_name = g_strdup_printf ("%s (%s)", language, name); + + return display_name; +} + +static GDesktopAppInfo * +setup_app_info_for_id (const gchar *id) +{ + GDesktopAppInfo *app_info; + gchar *desktop_file_name; + gchar **strv; + + strv = g_strsplit (id, ":", 2); + desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]); + g_strfreev (strv); + + app_info = g_desktop_app_info_new (desktop_file_name); + g_free (desktop_file_name); + + return app_info; +} + +static void +input_chooser_repopulate (GtkListStore *active_sources_store) +{ + GtkBuilder *builder; + GtkListStore *model; + + if (!input_chooser) + return; + + builder = g_object_get_data (G_OBJECT (input_chooser), "builder"); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + gtk_list_store_clear (model); + populate_model (model, active_sources_store); +} + +static void +update_ibus_active_sources (GtkBuilder *builder) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type, *id; + gboolean ret; + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + model = tree_view_get_actual_model (tv); + + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { + IBusEngineDesc *engine_desc = NULL; + GDesktopAppInfo *app_info = NULL; + gchar *display_name = NULL; + + engine_desc = g_hash_table_lookup (ibus_engines, id); + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + NAME_COLUMN, display_name, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + } + + g_free (type); + g_free (id); + + ret = gtk_tree_model_iter_next (model, &iter); + } + + input_chooser_repopulate (GTK_LIST_STORE (model)); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + GtkBuilder *builder) +{ + gboolean show_all_sources; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (ibus, result, &error); + + g_clear_object (&ibus_cancellable); + + if (!list && error) + { + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + show_all_sources = g_settings_get_boolean (input_sources_settings, "show-all-sources"); + + /* Maps engine ids to engine description objects */ + ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) + { + IBusEngineDesc *engine = l->data; + const gchar *engine_id = ibus_engine_desc_get_name (engine); + + if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); + else + g_object_unref (engine); + } + g_list_free (list); + + update_ibus_active_sources (builder); +} + +static void +fetch_ibus_engines (GtkBuilder *builder) +{ + ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (ibus, + -1, + ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + builder); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (ibus, fetch_ibus_engines, builder); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} + +static void +on_shell_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer data) +{ + GtkBuilder *builder = data; + + if (!ibus) + { + ibus = ibus_bus_new_async (); + if (ibus_bus_is_connected (ibus)) + fetch_ibus_engines (builder); + else + g_signal_connect_swapped (ibus, "connected", + G_CALLBACK (fetch_ibus_engines), builder); + } + maybe_start_ibus (); +} +#endif /* HAVE_IBUS */ + +static gboolean +add_source_to_table (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GHashTable *hash = data; + gchar *type; + gchar *id; + + gtk_tree_model_get (model, iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + g_hash_table_add (hash, g_strconcat (type, id, NULL)); + + g_free (type); + g_free (id); + + return FALSE; +} + +static void +populate_model (GtkListStore *store, + GtkListStore *active_sources_store) +{ + GHashTable *active_sources_table; + GtkTreeIter iter; + const gchar *name; + GList *sources, *tmp; + gchar *source_id = NULL; + + active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources_store), + add_source_to_table, + active_sources_table); + + sources = gnome_xkb_info_get_all_layouts (xkb_info); + + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_XKB, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data, + &name, NULL, NULL, NULL); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB, + ID_COLUMN, tmp->data, + -1); + } + g_free (source_id); + + g_list_free (sources); + +#ifdef HAVE_IBUS + if (ibus_engines) + { + gchar *display_name; + + sources = g_hash_table_get_keys (ibus_engines); + + source_id = NULL; + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_IBUS, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS, + ID_COLUMN, tmp->data, + -1); + g_free (display_name); + } + g_free (source_id); + + g_list_free (sources); + } +#endif + + g_hash_table_destroy (active_sources_table); +} + +static void +populate_with_active_sources (GtkListStore *store) +{ + GVariant *sources; + GVariantIter iter; + const gchar *name; + const gchar *type; + const gchar *id; + gchar *display_name; + GDesktopAppInfo *app_info; + GtkTreeIter tree_iter; + + sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) + { + display_name = NULL; + app_info = NULL; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (!name) + { + g_warning ("Couldn't find XKB input source '%s'", id); + continue; + } + display_name = g_strdup (name); + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + continue; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + continue; + } + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set (store, &tree_iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + + g_variant_unref (sources); +} + +static void +update_configuration (GtkTreeModel *model) +{ + GtkTreeIter iter; + gchar *type; + gchar *id; + GVariantBuilder builder; + GVariant *old_sources; + const gchar *old_current_type; + const gchar *old_current_id; + guint old_current_index; + guint old_n_sources; + guint index; + + old_sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + old_current_index = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE); + old_n_sources = g_variant_n_children (old_sources); + + if (old_n_sources > 0 && old_current_index < old_n_sources) + { + g_variant_get_child (old_sources, + old_current_index, + "(&s&s)", + &old_current_type, + &old_current_id); + } + else + { + old_current_type = ""; + old_current_id = ""; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); + index = 0; + gtk_tree_model_get_iter_first (model, &iter); + do + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + if (index != old_current_index && + g_str_equal (type, old_current_type) && + g_str_equal (id, old_current_id)) + { + g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, index); + } + g_variant_builder_add (&builder, "(ss)", type, id); + g_free (type); + g_free (id); + index += 1; + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); + g_settings_apply (input_sources_settings); + + g_variant_unref (old_sources); +} + +static gboolean +get_selected_iter (GtkBuilder *builder, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + return gtk_tree_selection_get_selected (selection, model, iter); +} + +static gint +idx_from_model_iter (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gint idx; + + path = gtk_tree_model_get_path (model, iter); + if (path == NULL) + return -1; + + idx = gtk_tree_path_get_indices (path)[0]; + gtk_tree_path_free (path); + + return idx; +} + +static void +update_button_sensitivity (GtkBuilder *builder) +{ + GtkWidget *remove_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *show_button; + GtkWidget *settings_button; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gint n_active; + gint index; + gboolean settings_sensitive; + GDesktopAppInfo *app_info; + + remove_button = WID("input_source_remove"); + show_button = WID("input_source_show"); + up_button = WID("input_source_move_up"); + down_button = WID("input_source_move_down"); + settings_button = WID("input_source_settings"); + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL); + + if (get_selected_iter (builder, &model, &iter)) + { + index = idx_from_model_iter (model, &iter); + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + } + else + { + index = -1; + app_info = NULL; + } + + settings_sensitive = (index >= 0 && app_info != NULL); + + if (app_info) + g_object_unref (app_info); + + gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1); + gtk_widget_set_sensitive (show_button, index >= 0); + gtk_widget_set_sensitive (up_button, index > 0); + gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); + gtk_widget_set_visible (settings_button, settings_sensitive); +} + +static void +set_selected_path (GtkBuilder *builder, + GtkTreePath *path) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + gtk_tree_selection_select_path (selection, path); +} + +static GtkTreeModel * +tree_view_get_actual_model (GtkTreeView *tv) +{ + GtkTreeModel *filtered_store; + + filtered_store = gtk_tree_view_get_model (tv); + + return gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered_store)); +} + +static void +chooser_response (GtkWidget *chooser, gint response_id, gpointer data) +{ + GtkBuilder *builder = data; + + if (response_id == GTK_RESPONSE_OK) + { + GtkTreeModel *model; + GtkTreeIter iter; + + if (input_chooser_get_selected (chooser, &model, &iter)) + { + GtkTreeView *tv; + GtkListStore *child_model; + GtkTreeIter child_iter, filter_iter; + gchar *name; + gchar *type; + gchar *id; + GDesktopAppInfo *app_info = NULL; + + gtk_tree_model_get (model, &iter, + NAME_COLUMN, &name, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + +#ifdef HAVE_IBUS + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + app_info = setup_app_info_for_id (id); +#endif + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + child_model = GTK_LIST_STORE (tree_view_get_actual_model (tv)); + + gtk_list_store_append (child_model, &child_iter); + + gtk_list_store_set (child_model, &child_iter, + NAME_COLUMN, name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (name); + g_free (type); + g_free (id); + if (app_info) + g_object_unref (app_info); + + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tv)), + &filter_iter, + &child_iter); + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tv), &filter_iter); + + update_button_sensitivity (builder); + update_configuration (GTK_TREE_MODEL (child_model)); + } + else + { + g_debug ("nothing selected, nothing added"); + } + } + + gtk_widget_destroy (GTK_WIDGET (chooser)); +} + +static void +add_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkWidget *chooser; + GtkWidget *toplevel; + GtkWidget *treeview; + GtkListStore *active_sources; + + g_debug ("add an input source"); + + toplevel = gtk_widget_get_toplevel (WID ("region_notebook")); + treeview = WID ("active_input_sources"); + active_sources = GTK_LIST_STORE (tree_view_get_actual_model (GTK_TREE_VIEW (treeview))); + + chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources); + g_signal_connect (chooser, "response", + G_CALLBACK (chooser_response), builder); +} + +static void +remove_selected_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter child_iter; + GtkTreePath *path; + + g_debug ("remove selected input source"); + + if (get_selected_iter (builder, &model, &iter) == FALSE) + return; + + path = gtk_tree_model_get_path (model, &iter); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_list_store_remove (GTK_LIST_STORE (child_model), &child_iter); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + gtk_tree_path_prev (path); + + set_selected_path (builder, path); + + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_up (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, prev; + GtkTreeIter child_iter, child_prev; + GtkTreePath *path; + + g_debug ("move selected input source up"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + prev = iter; + if (!gtk_tree_model_iter_previous (model, &prev)) + return; + + path = gtk_tree_model_get_path (model, &prev); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_prev, + &prev); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_prev); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_down (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, next; + GtkTreeIter child_iter, child_next; + GtkTreePath *path; + + g_debug ("move selected input source down"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + next = iter; + if (!gtk_tree_model_iter_next (model, &next)) + return; + + path = gtk_tree_model_get_path (model, &next); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_next, + &next); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_next); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +show_selected_layout (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *id; + gchar *kbd_viewer_args; + const gchar *xkb_layout; + const gchar *xkb_variant; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, NULL, NULL, &xkb_layout, &xkb_variant); + + if (!xkb_layout || !xkb_layout[0]) + { + g_warning ("Couldn't find XKB input source '%s'", id); + goto exit; + } + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + xkb_layout = ibus_engine_desc_get_layout (engine_desc); + xkb_variant = ""; + } + else + { + g_warning ("Couldn't find IBus input source '%s'", id); + goto exit; + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + goto exit; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + goto exit; + } + + if (xkb_variant[0]) + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", + xkb_layout, xkb_variant); + else + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", + xkb_layout); + + g_spawn_command_line_async (kbd_viewer_args, NULL); + + g_free (kbd_viewer_args); + exit: + g_free (type); + g_free (id); +} + +static void +show_selected_settings (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + GdkAppLaunchContext *ctx; + GDesktopAppInfo *app_info; + gchar *id; + GError *error = NULL; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + + if (!app_info) + return; + + ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); + gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ()); + + gtk_tree_model_get (model, &iter, ID_COLUMN, &id, -1); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx), + "IBUS_ENGINE_NAME", + id); + g_free (id); + + if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) + { + g_warning ("Failed to launch input source setup: %s", error->message); + g_error_free (error); + } + + g_object_unref (ctx); + g_object_unref (app_info); +} + +static gboolean +go_to_shortcuts (GtkLinkButton *button, + CcRegionPanel *panel) +{ + CcShell *shell; + const gchar *argv[] = { "shortcuts", "Typing", NULL }; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error)) + { + g_warning ("Failed to activate Keyboard panel: %s", error->message); + g_error_free (error); + } + + return TRUE; +} + +static void +input_sources_changed (GSettings *settings, + gchar *key, + GtkBuilder *builder) +{ + GtkWidget *treeview; + GtkTreeModel *store; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeModel *model; + + treeview = WID("active_input_sources"); + store = tree_view_get_actual_model (GTK_TREE_VIEW (treeview)); + + if (get_selected_iter (builder, &model, &iter)) + path = gtk_tree_model_get_path (model, &iter); + else + path = NULL; + + gtk_list_store_clear (GTK_LIST_STORE (store)); + populate_with_active_sources (GTK_LIST_STORE (store)); + + if (path) + { + set_selected_path (builder, path); + gtk_tree_path_free (path); + } +} + +static void +update_shortcut_label (GtkWidget *widget, + const char *value) +{ + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + if (value == NULL || *value == '\0') + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +update_shortcuts (GtkBuilder *builder) +{ + char **previous, **next; + GSettings *settings; + + settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); + + previous = g_settings_get_strv (settings, "switch-input-source-backward"); + next = g_settings_get_strv (settings, "switch-input-source"); + + update_shortcut_label (WID ("prev-source-shortcut-label"), previous[0]); + update_shortcut_label (WID ("next-source-shortcut-label"), next[0]); + + g_strfreev (previous); + g_strfreev (next); +} + +static gboolean +active_sources_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *display_name; + + gtk_tree_model_get (model, iter, NAME_COLUMN, &display_name, -1); + + if (!display_name) + return FALSE; + + g_free (display_name); + + return TRUE; +} + +void +setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *panel) +{ + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkListStore *store; + GtkTreeModel *filtered_store; + GtkTreeSelection *selection; + + /* set up the list of active inputs */ + treeview = WID("active_input_sources"); + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_DESKTOP_APP_INFO); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); + g_settings_delay (input_sources_settings); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) g_object_unref, input_sources_settings); + + if (!xkb_info) + xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + builder, + NULL); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) clear_ibus, NULL); +#endif + + populate_with_active_sources (store); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect_swapped (selection, "changed", + G_CALLBACK (update_button_sensitivity), builder); + + /* Some input source types might have their info loaded + * asynchronously. In that case we don't want to show them + * immediately so we use a filter model on top of the real model + * which mirrors the GSettings key. */ + filtered_store = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered_store), + active_sources_visible_func, + NULL, + NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), filtered_store); + + /* set up the buttons */ + g_signal_connect (WID("input_source_add"), "clicked", + G_CALLBACK (add_input), builder); + g_signal_connect (WID("input_source_remove"), "clicked", + G_CALLBACK (remove_selected_input), builder); + g_signal_connect (WID("input_source_move_up"), "clicked", + G_CALLBACK (move_selected_input_up), builder); + g_signal_connect (WID("input_source_move_down"), "clicked", + G_CALLBACK (move_selected_input_down), builder); + g_signal_connect (WID("input_source_show"), "clicked", + G_CALLBACK (show_selected_layout), builder); + g_signal_connect (WID("input_source_settings"), "clicked", + G_CALLBACK (show_selected_settings), builder); + + /* use an em dash is no shortcut */ + update_shortcuts (builder); + + g_signal_connect (WID("jump-to-shortcuts"), "activate-link", + G_CALLBACK (go_to_shortcuts), panel); + + g_signal_connect (G_OBJECT (input_sources_settings), + "changed::" KEY_INPUT_SOURCES, + G_CALLBACK (input_sources_changed), + builder); + + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-true"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-false"), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + /* because we are in delay-apply mode */ + g_signal_connect_swapped (WID("per-window-radio-true"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); + g_signal_connect_swapped (WID("per-window-radio-false"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); +} + +static void +filter_clear (GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + gpointer user_data) +{ + gtk_entry_set_text (entry, ""); +} + +static gchar **search_pattern_list; + +static void +filter_changed (GtkBuilder *builder) +{ + GtkTreeModelFilter *filtered_model; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreeIter selected_iter; + GtkWidget *filter_entry; + const gchar *pattern; + gchar *upattern; + + filter_entry = WID ("input_source_filter"); + pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry)); + upattern = g_utf8_strup (pattern, -1); + if (!g_strcmp0 (pattern, "")) + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-find-symbolic", + "secondary-icon-activatable", FALSE, + "secondary-icon-sensitive", FALSE, + NULL); + else + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-clear-symbolic", + "secondary-icon-activatable", TRUE, + "secondary-icon-sensitive", TRUE, + NULL); + + if (search_pattern_list != NULL) + g_strfreev (search_pattern_list); + + search_pattern_list = g_strsplit (upattern, " ", -1); + g_free (upattern); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + gtk_tree_model_filter_refilter (filtered_model); + + tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list")); + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model), + &selected_iter); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free (path); + } + else + { + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkBuilder *builder) +{ + gtk_widget_set_sensitive (WID ("ok-button"), + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkBuilder *builder) +{ + GtkWidget *add_button; + GtkWidget *dialog; + + add_button = WID ("ok-button"); + dialog = WID ("input_source_chooser"); + if (gtk_widget_is_sensitive (add_button)) + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +entry_activated (GtkBuilder *builder, + gpointer data) +{ + row_activated (NULL, NULL, NULL, builder); +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name = NULL; + gchar **pattern; + gboolean rv = TRUE; + + if (search_pattern_list == NULL || search_pattern_list[0] == NULL) + return TRUE; + + gtk_tree_model_get (model, iter, + NAME_COLUMN, &name, + -1); + + pattern = search_pattern_list; + do { + gboolean is_pattern_found = FALSE; + gchar *udesc = g_utf8_strup (name, -1); + if (udesc != NULL && g_strstr_len (udesc, -1, *pattern)) + { + is_pattern_found = TRUE; + } + g_free (udesc); + + if (!is_pattern_found) + { + rv = FALSE; + break; + } + + } while (*++pattern != NULL); + + g_free (name); + + return rv; +} + +static GtkWidget * +input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources) +{ + GtkBuilder *builder; + GtkWidget *chooser; + GtkWidget *filtered_list; + GtkWidget *filter_entry; + GtkTreeViewColumn *visible_column; + GtkTreeSelection *selection; + GtkListStore *model; + GtkTreeModelFilter *filtered_model; + GtkTreeIter iter; + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, + GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui", + NULL); + chooser = WID ("input_source_chooser"); + input_chooser = chooser; + g_object_add_weak_pointer (G_OBJECT (chooser), (gpointer *) &input_chooser); + g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref); + + filtered_list = WID ("filtered_input_source_list"); + filter_entry = WID ("input_source_filter"); + + g_object_set_data (G_OBJECT (chooser), + "filtered_input_source_list", filtered_list); + visible_column = + gtk_tree_view_column_new_with_attributes ("Input Sources", + gtk_cell_renderer_text_new (), + "text", NAME_COLUMN, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window); + + gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list), + visible_column); + /* We handle searching ourselves, thank you. */ + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1); + + g_signal_connect_swapped (G_OBJECT (filter_entry), "activate", + G_CALLBACK (entry_activated), builder); + g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text", + G_CALLBACK (filter_changed), builder); + + g_signal_connect (G_OBJECT (filter_entry), "icon-release", + G_CALLBACK (filter_clear), NULL); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + populate_model (model, active_sources); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + NAME_COLUMN, GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (filtered_model, + filter_func, + NULL, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list)); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), builder); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + + g_signal_connect (G_OBJECT (filtered_list), "row-activated", + G_CALLBACK (row_activated), builder); + + gtk_widget_grab_focus (filter_entry); + + gtk_widget_show (chooser); + + return chooser; +} + +static gboolean +input_chooser_get_selected (GtkWidget *dialog, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkWidget *tv; + GtkTreeSelection *selection; + + tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list"); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + + return gtk_tree_selection_get_selected (selection, model, iter); +} diff -Nru gnome-control-center-3.6.3/.pc/git-fix-background-panel-crash.patch/panels/background/bg-pictures-source.c gnome-control-center-3.6.3/.pc/git-fix-background-panel-crash.patch/panels/background/bg-pictures-source.c --- gnome-control-center-3.6.3/.pc/git-fix-background-panel-crash.patch/panels/background/bg-pictures-source.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-fix-background-panel-crash.patch/panels/background/bg-pictures-source.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,585 @@ +/* bg-pictures-source.c */ +/* + * Copyright (C) 2010 Intel, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Thomas Wood + * + */ + +#include "bg-pictures-source.h" + +#include "cc-background-item.h" + +#include +#include +#include +#include + +G_DEFINE_TYPE (BgPicturesSource, bg_pictures_source, BG_TYPE_SOURCE) + +#define PICTURES_SOURCE_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), BG_TYPE_PICTURES_SOURCE, BgPicturesSourcePrivate)) + +#define ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_NAME "," \ + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE + +struct _BgPicturesSourcePrivate +{ + GCancellable *cancellable; + + GnomeDesktopThumbnailFactory *thumb_factory; + + GHashTable *known_items; +}; + +const char * const content_types[] = { + "image/png", + "image/jpeg", + "image/bmp", + "image/svg+xml", + NULL +}; + +static char *bg_pictures_source_get_unique_filename (const char *uri); + +static void +bg_pictures_source_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +bg_pictures_source_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +bg_pictures_source_dispose (GObject *object) +{ + BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (object)->priv; + + if (priv->cancellable) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + if (priv->thumb_factory) + { + g_object_unref (priv->thumb_factory); + priv->thumb_factory = NULL; + } + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->dispose (object); +} + +static void +bg_pictures_source_finalize (GObject *object) +{ + BgPicturesSource *bg_source = BG_PICTURES_SOURCE (object); + + if (bg_source->priv->thumb_factory) + { + g_object_unref (bg_source->priv->thumb_factory); + bg_source->priv->thumb_factory = NULL; + } + + if (bg_source->priv->known_items) + { + g_hash_table_destroy (bg_source->priv->known_items); + bg_source->priv->known_items = NULL; + } + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->finalize (object); +} + +static void +bg_pictures_source_class_init (BgPicturesSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (BgPicturesSourcePrivate)); + + object_class->get_property = bg_pictures_source_get_property; + object_class->set_property = bg_pictures_source_set_property; + object_class->dispose = bg_pictures_source_dispose; + object_class->finalize = bg_pictures_source_finalize; +} + +static int +sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + BgPicturesSource *bg_source) +{ + CcBackgroundItem *item_a; + CcBackgroundItem *item_b; + const char *name_a; + const char *name_b; + int retval; + + gtk_tree_model_get (model, a, + 1, &item_a, + -1); + gtk_tree_model_get (model, b, + 1, &item_b, + -1); + + name_a = cc_background_item_get_name (item_a); + name_b = cc_background_item_get_name (item_b); + + retval = g_utf8_collate (name_a, name_b); + + g_object_unref (item_a); + g_object_unref (item_b); + + return retval; +} + +static void +picture_scaled (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + GError *error = NULL; + GdkPixbuf *pixbuf; + const char *source_url; + const char *software; + GtkTreeIter iter; + GtkListStore *store; + + pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error); + if (pixbuf == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to load image: %s", error->message); + + g_error_free (error); + return; + } + + /* since we were not cancelled, we can now cast user_data + * back to BgPicturesSource. + */ + bg_source = BG_PICTURES_SOURCE (user_data); + store = bg_source_get_liststore (BG_SOURCE (bg_source)); + item = g_object_get_data (source_object, "item"); + + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), + 1, + (GtkTreeIterCompareFunc)sort_func, + bg_source, + NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + 1, + GTK_SORT_ASCENDING); + + /* Ignore screenshots */ + software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software"); + if (software != NULL && + g_str_equal (software, "gnome-screenshot")) + { + g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot", + cc_background_item_get_uri (item)); + g_object_unref (pixbuf); + g_object_unref (item); + return; + } + + cc_background_item_load (item, NULL); + + /* insert the item into the liststore */ + gtk_list_store_insert_with_values (store, &iter, 0, + 0, pixbuf, + 1, item, + -1); + source_url = cc_background_item_get_source_url (item); + if (source_url != NULL) + { + g_hash_table_insert (bg_source->priv->known_items, + bg_pictures_source_get_unique_filename (source_url), GINT_TO_POINTER (TRUE)); + } + else + { + char *cache_path; + GFile *file, *parent, *dir; + + cache_path = bg_pictures_source_get_cache_path (); + dir = g_file_new_for_path (cache_path); + g_free (cache_path); + + file = g_file_new_for_uri (cc_background_item_get_uri (item)); + parent = g_file_get_parent (file); + + if (g_file_equal (parent, dir)) + { + char *basename; + basename = g_file_get_basename (file); + g_hash_table_insert (bg_source->priv->known_items, + basename, GINT_TO_POINTER (TRUE)); + } + g_object_unref (file); + g_object_unref (parent); + } + + g_object_unref (pixbuf); +} + +static void +picture_opened_for_read (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + GFileInputStream *stream; + GError *error = NULL; + + item = g_object_get_data (source_object, "item"); + stream = g_file_read_finish (G_FILE (source_object), res, &error); + if (stream == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + char *filename = g_file_get_path (G_FILE (source_object)); + g_warning ("Failed to load picture '%s': %s", filename, error->message); + g_free (filename); + } + + g_error_free (error); + g_object_unref (item); + return; + } + + /* since we were not cancelled, we can now cast user_data + * back to BgPicturesSource. + */ + bg_source = BG_PICTURES_SOURCE (user_data); + + g_object_set_data (G_OBJECT (stream), "item", item); + gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (stream), + THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, + TRUE, + bg_source->priv->cancellable, + picture_scaled, bg_source); + g_object_unref (stream); +} + +static gboolean +in_content_types (const char *content_type) +{ + guint i; + for (i = 0; content_types[i]; i++) + if (g_str_equal (content_types[i], content_type)) + return TRUE; + return FALSE; +} + +static gboolean +add_single_file (BgPicturesSource *bg_source, + GFile *file, + GFileInfo *info, + const char *source_uri) +{ + const gchar *content_type; + CcBackgroundItem *item; + char *uri; + + /* find png and jpeg files */ + content_type = g_file_info_get_content_type (info); + + if (!content_type) + return FALSE; + if (!in_content_types (content_type)) + return FALSE; + + /* create a new CcBackgroundItem */ + uri = g_file_get_uri (file); + item = cc_background_item_new (uri); + g_free (uri); + g_object_set (G_OBJECT (item), + "flags", CC_BACKGROUND_ITEM_HAS_URI | CC_BACKGROUND_ITEM_HAS_SHADING, + "shading", G_DESKTOP_BACKGROUND_SHADING_SOLID, + "placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM, + NULL); + if (source_uri != NULL && !g_file_is_native (file)) + g_object_set (G_OBJECT (item), "source-url", source_uri, NULL); + + g_object_set_data (G_OBJECT (file), "item", item); + g_file_read_async (file, G_PRIORITY_DEFAULT, + bg_source->priv->cancellable, + picture_opened_for_read, bg_source); + g_object_unref (file); + return TRUE; +} + +gboolean +bg_pictures_source_add (BgPicturesSource *bg_source, + const char *uri) +{ + GFile *file; + GFileInfo *info; + gboolean retval; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, ATTRIBUTES, G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (info == NULL) + return FALSE; + + retval = add_single_file (bg_source, file, info, uri); + + return retval; +} + +gboolean +bg_pictures_source_remove (BgPicturesSource *bg_source, + CcBackgroundItem *item) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean cont; + const char *uri; + gboolean retval; + + retval = FALSE; + model = GTK_TREE_MODEL (bg_source_get_liststore (BG_SOURCE (bg_source))); + uri = cc_background_item_get_uri (item); + + cont = gtk_tree_model_get_iter_first (model, &iter); + while (cont) + { + CcBackgroundItem *tmp_item; + const char *tmp_uri; + + gtk_tree_model_get (model, &iter, 1, &tmp_item, -1); + tmp_uri = cc_background_item_get_uri (tmp_item); + if (g_str_equal (tmp_uri, uri)) + { + GFile *file; + char *uuid; + + file = g_file_new_for_uri (uri); + uuid = g_file_get_basename (file); + g_hash_table_insert (bg_source->priv->known_items, + uuid, NULL); + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + retval = TRUE; + g_file_trash (file, NULL, NULL); + g_object_unref (file); + break; + } + g_object_unref (tmp_item); + cont = gtk_tree_model_iter_next (model, &iter); + } + return retval; +} + +static void +file_info_async_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source = BG_PICTURES_SOURCE (user_data); + GList *files, *l; + GError *err = NULL; + GFile *parent; + files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source), + res, + &err); + + if (err) + { + g_warning ("Could not get pictures file information: %s", err->message); + g_error_free (err); + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); + return; + } + + parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); + + /* iterate over the available files */ + for (l = files; l; l = g_list_next (l)) + { + GFileInfo *info = l->data; + GFile *file; + + file = g_file_get_child (parent, g_file_info_get_name (info)); + + add_single_file (bg_source, file, info, NULL); + } + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); +} + +static void +dir_enum_async_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSourcePrivate *priv = BG_PICTURES_SOURCE (user_data)->priv; + GFileEnumerator *enumerator; + GError *err = NULL; + + enumerator = g_file_enumerate_children_finish (G_FILE (source), res, &err); + + if (err) + { + if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) == FALSE) + g_warning ("Could not fill pictures source: %s", err->message); + g_error_free (err); + return; + } + + /* get the files */ + g_file_enumerator_next_files_async (enumerator, + G_MAXINT, + G_PRIORITY_LOW, + priv->cancellable, + file_info_async_ready, + user_data); +} + +char * +bg_pictures_source_get_cache_path (void) +{ + return g_build_filename (g_get_user_cache_dir (), + "gnome-control-center", + "backgrounds", + NULL); +} + +static char * +bg_pictures_source_get_unique_filename (const char *uri) +{ + GChecksum *csum; + char *ret; + + csum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (csum, (guchar *) uri, -1); + ret = g_strdup (g_checksum_get_string (csum)); + g_checksum_free (csum); + + return ret; +} + +char * +bg_pictures_source_get_unique_path (const char *uri) +{ + GFile *parent, *file; + char *cache_path; + char *filename; + char *ret; + + cache_path = bg_pictures_source_get_cache_path (); + parent = g_file_new_for_path (cache_path); + g_free (cache_path); + + filename = bg_pictures_source_get_unique_filename (uri); + file = g_file_get_child (parent, filename); + g_free (filename); + ret = g_file_get_path (file); + g_object_unref (file); + + return ret; +} + +gboolean +bg_pictures_source_is_known (BgPicturesSource *bg_source, + const char *uri) +{ + gboolean retval; + char *uuid; + + uuid = bg_pictures_source_get_unique_filename (uri); + retval = (GPOINTER_TO_INT (g_hash_table_lookup (bg_source->priv->known_items, uuid))); + g_free (uuid); + + return retval; +} + +static void +bg_pictures_source_init (BgPicturesSource *self) +{ + const gchar *pictures_path; + BgPicturesSourcePrivate *priv; + GFile *dir; + char *cache_path; + + priv = self->priv = PICTURES_SOURCE_PRIVATE (self); + + priv->cancellable = g_cancellable_new (); + priv->known_items = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); + + pictures_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); + dir = g_file_new_for_path (pictures_path); + g_file_enumerate_children_async (dir, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, priv->cancellable, + dir_enum_async_ready, self); + g_object_unref (dir); + + cache_path = bg_pictures_source_get_cache_path (); + dir = g_file_new_for_path (cache_path); + g_file_enumerate_children_async (dir, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, priv->cancellable, + dir_enum_async_ready, self); + g_object_unref (dir); + + priv->thumb_factory = + gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); +} + +BgPicturesSource * +bg_pictures_source_new (void) +{ + return g_object_new (BG_TYPE_PICTURES_SOURCE, NULL); +} + +const char * const * +bg_pictures_get_support_content_types (void) +{ + return content_types; +} diff -Nru gnome-control-center-3.6.3/.pc/git_hide_unavailable_layout_settings_btn.patch/panels/region/gnome-region-panel-input.c gnome-control-center-3.6.3/.pc/git_hide_unavailable_layout_settings_btn.patch/panels/region/gnome-region-panel-input.c --- gnome-control-center-3.6.3/.pc/git_hide_unavailable_layout_settings_btn.patch/panels/region/gnome-region-panel-input.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_hide_unavailable_layout_settings_btn.patch/panels/region/gnome-region-panel-input.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1580 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by: Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#include +#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#ifdef HAVE_IBUS +#include +#endif + +#include "gdm-languages.h" +#include "gnome-region-panel-input.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s)) + +#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" + +#define KEY_CURRENT_INPUT_SOURCE "current" +#define KEY_INPUT_SOURCES "sources" + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +enum { + NAME_COLUMN, + TYPE_COLUMN, + ID_COLUMN, + SETUP_COLUMN, + N_COLUMNS +}; + +static GSettings *input_sources_settings = NULL; +static GnomeXkbInfo *xkb_info = NULL; +static GtkWidget *input_chooser = NULL; /* weak pointer */ + +#ifdef HAVE_IBUS +static IBusBus *ibus = NULL; +static GHashTable *ibus_engines = NULL; +static GCancellable *ibus_cancellable = NULL; +static guint shell_name_watch_id = 0; + +static const gchar *supported_ibus_engines[] = { + /* Simplified Chinese */ + "pinyin", + "bopomofo", + "wubi", + "erbi", + /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ + "libpinyin", + "libbopomofo", + + /* Traditional Chinese */ + /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ + "chewing", + "cangjie5", + "cangjie3", + "quick5", + "quick3", + "stroke5", + + /* Japanese */ + "anthy", + "mozc-jp", + "skk", + + /* Korean */ + "hangul", + + /* Thai */ + "m17n:th:kesmanee", + "m17n:th:pattachote", + "m17n:th:tis820", + + /* Vietnamese */ + "m17n:vi:tcvn", + "m17n:vi:telex", + "m17n:vi:viqr", + "m17n:vi:vni", + "Unikey", + + /* Sinhala */ + "m17n:si:wijesekera", + "m17n:si:phonetic-dynamic", + "m17n:si:trans", + "sayura", + + /* Indic */ + /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ + + /* Assamese */ + "m17n:as:phonetic", + "m17n:as:inscript", + "m17n:as:itrans", + + /* Bengali */ + "m17n:bn:inscript", + "m17n:bn:itrans", + "m17n:bn:probhat", + + /* Gujarati */ + "m17n:gu:inscript", + "m17n:gu:itrans", + "m17n:gu:phonetic", + + /* Hindi */ + "m17n:hi:inscript", + "m17n:hi:itrans", + "m17n:hi:phonetic", + "m17n:hi:remington", + "m17n:hi:typewriter", + "m17n:hi:vedmata", + + /* Kannada */ + "m17n:kn:kgp", + "m17n:kn:inscript", + "m17n:kn:itrans", + + /* Kashmiri */ + "m17n:ks:inscript", + + /* Maithili */ + "m17n:mai:inscript", + + /* Malayalam */ + "m17n:ml:inscript", + "m17n:ml:itrans", + "m17n:ml:mozhi", + "m17n:ml:swanalekha", + + /* Marathi */ + "m17n:mr:inscript", + "m17n:mr:itrans", + "m17n:mr:phonetic", + + /* Nepali */ + "m17n:ne:rom", + "m17n:ne:trad", + + /* Oriya */ + "m17n:or:inscript", + "m17n:or:itrans", + "m17n:or:phonetic", + + /* Punjabi */ + "m17n:pa:inscript", + "m17n:pa:itrans", + "m17n:pa:phonetic", + "m17n:pa:jhelum", + + /* Sanskrit */ + "m17n:sa:harvard-kyoto", + + /* Sindhi */ + "m17n:sd:inscript", + + /* Tamil */ + "m17n:ta:tamil99", + "m17n:ta:inscript", + "m17n:ta:itrans", + "m17n:ta:phonetic", + "m17n:ta:lk-renganathan", + "m17n:ta:vutam", + "m17n:ta:typewriter", + + /* Telugu */ + "m17n:te:inscript", + "m17n:te:apple", + "m17n:te:pothana", + "m17n:te:rts", + + /* Urdu */ + "m17n:ur:phonetic", + + /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ + "m17n:as:inscript2", + "m17n:bn:inscript2", + "m17n:brx:inscript2-deva", + "m17n:doi:inscript2-deva", + "m17n:gu:inscript2", + "m17n:hi:inscript2", + "m17n:kn:inscript2", + "m17n:kok:inscript2-deva", + "m17n:mai:inscript2", + "m17n:ml:inscript2", + "m17n:mni:inscript2-beng", + "m17n:mni:inscript2-mtei", + "m17n:mr:inscript2", + "m17n:ne:inscript2-deva", + "m17n:or:inscript2", + "m17n:pa:inscript2-guru", + "m17n:sa:inscript2", + "m17n:sat:inscript2-deva", + "m17n:sat:inscript2-olck", + "m17n:sd:inscript2-deva", + "m17n:ta:inscript2", + "m17n:te:inscript2", + + /* No corresponding XKB map available for the languages */ + + /* Chinese Yi */ + "m17n:ii:phonetic", + + /* Tai-Viet */ + "m17n:tai:sonla", + + /* Kazakh in Arabic script */ + "m17n:kk:arabic", + + /* Yiddish */ + "m17n:yi:yivo", + + /* Canadian Aboriginal languages */ + "m17n:ath:phonetic", + "m17n:bla:phonetic", + "m17n:cr:western", + "m17n:iu:phonetic", + "m17n:nsk:phonetic", + "m17n:oj:phonetic", + + /* Non-trivial engines, like transliteration-based instead of + keymap-based. Confirmation needed that the engines below are + actually used by local language users. */ + + /* Tibetan */ + "m17n:bo:ewts", + "m17n:bo:tcrc", + "m17n:bo:wylie", + + /* Esperanto */ + "m17n:eo:h-f", + "m17n:eo:h", + "m17n:eo:plena", + "m17n:eo:q", + "m17n:eo:vi", + "m17n:eo:x", + + /* Amharic */ + "m17n:am:sera", + + /* Russian */ + "m17n:ru:translit", + + /* Classical Greek */ + "m17n:grc:mizuochi", + + /* Lao */ + "m17n:lo:lrt", + + /* Postfix modifier input methods */ + "m17n:da:post", + "m17n:sv:post", + NULL +}; +#endif /* HAVE_IBUS */ + +static void populate_model (GtkListStore *store, + GtkListStore *active_sources_store); +static GtkWidget *input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources); +static gboolean input_chooser_get_selected (GtkWidget *chooser, + GtkTreeModel **model, + GtkTreeIter *iter); +static GtkTreeModel *tree_view_get_actual_model (GtkTreeView *tv); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +#ifdef HAVE_IBUS +static void +clear_ibus (void) +{ + if (shell_name_watch_id > 0) + { + g_bus_unwatch_name (shell_name_watch_id); + shell_name_watch_id = 0; + } + g_cancellable_cancel (ibus_cancellable); + g_clear_object (&ibus_cancellable); + g_clear_pointer (&ibus_engines, g_hash_table_destroy); + g_clear_object (&ibus); +} + +static gchar * +engine_get_display_name (IBusEngineDesc *engine_desc) +{ + const gchar *name; + const gchar *language_code; + const gchar *language; + gchar *display_name; + + name = ibus_engine_desc_get_longname (engine_desc); + language_code = ibus_engine_desc_get_language (engine_desc); + language = ibus_get_language_name (language_code); + + display_name = g_strdup_printf ("%s (%s)", language, name); + + return display_name; +} + +static GDesktopAppInfo * +setup_app_info_for_id (const gchar *id) +{ + GDesktopAppInfo *app_info; + gchar *desktop_file_name; + gchar **strv; + + strv = g_strsplit (id, ":", 2); + desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]); + g_strfreev (strv); + + app_info = g_desktop_app_info_new (desktop_file_name); + g_free (desktop_file_name); + + return app_info; +} + +static void +input_chooser_repopulate (GtkListStore *active_sources_store) +{ + GtkBuilder *builder; + GtkListStore *model; + + if (!input_chooser) + return; + + builder = g_object_get_data (G_OBJECT (input_chooser), "builder"); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + gtk_list_store_clear (model); + populate_model (model, active_sources_store); +} + +static void +update_ibus_active_sources (GtkBuilder *builder) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type, *id; + gboolean ret; + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + model = tree_view_get_actual_model (tv); + + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { + IBusEngineDesc *engine_desc = NULL; + GDesktopAppInfo *app_info = NULL; + gchar *display_name = NULL; + + engine_desc = g_hash_table_lookup (ibus_engines, id); + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + NAME_COLUMN, display_name, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + } + + g_free (type); + g_free (id); + + ret = gtk_tree_model_iter_next (model, &iter); + } + + input_chooser_repopulate (GTK_LIST_STORE (model)); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + GtkBuilder *builder) +{ + gboolean show_all_sources; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (ibus, result, &error); + + g_clear_object (&ibus_cancellable); + + if (!list && error) + { + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + show_all_sources = g_settings_get_boolean (input_sources_settings, "show-all-sources"); + + /* Maps engine ids to engine description objects */ + ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) + { + IBusEngineDesc *engine = l->data; + const gchar *engine_id = ibus_engine_desc_get_name (engine); + + if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); + else + g_object_unref (engine); + } + g_list_free (list); + + update_ibus_active_sources (builder); +} + +static void +fetch_ibus_engines (GtkBuilder *builder) +{ + ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (ibus, + -1, + ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + builder); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (ibus, fetch_ibus_engines, builder); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} + +static void +on_shell_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer data) +{ + GtkBuilder *builder = data; + + if (!ibus) + { + ibus = ibus_bus_new_async (); + if (ibus_bus_is_connected (ibus)) + fetch_ibus_engines (builder); + else + g_signal_connect_swapped (ibus, "connected", + G_CALLBACK (fetch_ibus_engines), builder); + } + maybe_start_ibus (); +} +#endif /* HAVE_IBUS */ + +static gboolean +add_source_to_table (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GHashTable *hash = data; + gchar *type; + gchar *id; + + gtk_tree_model_get (model, iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + g_hash_table_add (hash, g_strconcat (type, id, NULL)); + + g_free (type); + g_free (id); + + return FALSE; +} + +static void +populate_model (GtkListStore *store, + GtkListStore *active_sources_store) +{ + GHashTable *active_sources_table; + GtkTreeIter iter; + const gchar *name; + GList *sources, *tmp; + gchar *source_id = NULL; + + active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources_store), + add_source_to_table, + active_sources_table); + + sources = gnome_xkb_info_get_all_layouts (xkb_info); + + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_XKB, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data, + &name, NULL, NULL, NULL); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB, + ID_COLUMN, tmp->data, + -1); + } + g_free (source_id); + + g_list_free (sources); + +#ifdef HAVE_IBUS + if (ibus_engines) + { + gchar *display_name; + + sources = g_hash_table_get_keys (ibus_engines); + + source_id = NULL; + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_IBUS, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS, + ID_COLUMN, tmp->data, + -1); + g_free (display_name); + } + g_free (source_id); + + g_list_free (sources); + } +#endif + + g_hash_table_destroy (active_sources_table); +} + +static void +populate_with_active_sources (GtkListStore *store) +{ + GVariant *sources; + GVariantIter iter; + const gchar *name; + const gchar *type; + const gchar *id; + gchar *display_name; + GDesktopAppInfo *app_info; + GtkTreeIter tree_iter; + + sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) + { + display_name = NULL; + app_info = NULL; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (!name) + { + g_warning ("Couldn't find XKB input source '%s'", id); + continue; + } + display_name = g_strdup (name); + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + continue; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + continue; + } + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set (store, &tree_iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + + g_variant_unref (sources); +} + +static void +update_configuration (GtkTreeModel *model) +{ + GtkTreeIter iter; + gchar *type; + gchar *id; + GVariantBuilder builder; + GVariant *old_sources; + const gchar *old_current_type; + const gchar *old_current_id; + guint old_current_index; + guint old_n_sources; + guint index; + + old_sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + old_current_index = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE); + old_n_sources = g_variant_n_children (old_sources); + + if (old_n_sources > 0 && old_current_index < old_n_sources) + { + g_variant_get_child (old_sources, + old_current_index, + "(&s&s)", + &old_current_type, + &old_current_id); + } + else + { + old_current_type = ""; + old_current_id = ""; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); + index = 0; + gtk_tree_model_get_iter_first (model, &iter); + do + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + if (index != old_current_index && + g_str_equal (type, old_current_type) && + g_str_equal (id, old_current_id)) + { + g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, index); + } + g_variant_builder_add (&builder, "(ss)", type, id); + g_free (type); + g_free (id); + index += 1; + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); + g_settings_apply (input_sources_settings); + + g_variant_unref (old_sources); +} + +static gboolean +get_selected_iter (GtkBuilder *builder, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + return gtk_tree_selection_get_selected (selection, model, iter); +} + +static gint +idx_from_model_iter (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gint idx; + + path = gtk_tree_model_get_path (model, iter); + if (path == NULL) + return -1; + + idx = gtk_tree_path_get_indices (path)[0]; + gtk_tree_path_free (path); + + return idx; +} + +static void +update_button_sensitivity (GtkBuilder *builder) +{ + GtkWidget *remove_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *show_button; + GtkWidget *settings_button; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gint n_active; + gint index; + gboolean settings_sensitive; + GDesktopAppInfo *app_info; + + remove_button = WID("input_source_remove"); + show_button = WID("input_source_show"); + up_button = WID("input_source_move_up"); + down_button = WID("input_source_move_down"); + settings_button = WID("input_source_settings"); + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL); + + if (get_selected_iter (builder, &model, &iter)) + { + index = idx_from_model_iter (model, &iter); + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + } + else + { + index = -1; + app_info = NULL; + } + + settings_sensitive = (index >= 0 && app_info != NULL); + + if (app_info) + g_object_unref (app_info); + + gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1); + gtk_widget_set_sensitive (show_button, index >= 0); + gtk_widget_set_sensitive (up_button, index > 0); + gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); + gtk_widget_set_sensitive (settings_button, settings_sensitive); +} + +static void +set_selected_path (GtkBuilder *builder, + GtkTreePath *path) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + gtk_tree_selection_select_path (selection, path); +} + +static GtkTreeModel * +tree_view_get_actual_model (GtkTreeView *tv) +{ + GtkTreeModel *filtered_store; + + filtered_store = gtk_tree_view_get_model (tv); + + return gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered_store)); +} + +static void +chooser_response (GtkWidget *chooser, gint response_id, gpointer data) +{ + GtkBuilder *builder = data; + + if (response_id == GTK_RESPONSE_OK) + { + GtkTreeModel *model; + GtkTreeIter iter; + + if (input_chooser_get_selected (chooser, &model, &iter)) + { + GtkTreeView *tv; + GtkListStore *child_model; + GtkTreeIter child_iter, filter_iter; + gchar *name; + gchar *type; + gchar *id; + GDesktopAppInfo *app_info = NULL; + + gtk_tree_model_get (model, &iter, + NAME_COLUMN, &name, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + +#ifdef HAVE_IBUS + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + app_info = setup_app_info_for_id (id); +#endif + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + child_model = GTK_LIST_STORE (tree_view_get_actual_model (tv)); + + gtk_list_store_append (child_model, &child_iter); + + gtk_list_store_set (child_model, &child_iter, + NAME_COLUMN, name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (name); + g_free (type); + g_free (id); + if (app_info) + g_object_unref (app_info); + + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tv)), + &filter_iter, + &child_iter); + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tv), &filter_iter); + + update_button_sensitivity (builder); + update_configuration (GTK_TREE_MODEL (child_model)); + } + else + { + g_debug ("nothing selected, nothing added"); + } + } + + gtk_widget_destroy (GTK_WIDGET (chooser)); +} + +static void +add_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkWidget *chooser; + GtkWidget *toplevel; + GtkWidget *treeview; + GtkListStore *active_sources; + + g_debug ("add an input source"); + + toplevel = gtk_widget_get_toplevel (WID ("region_notebook")); + treeview = WID ("active_input_sources"); + active_sources = GTK_LIST_STORE (tree_view_get_actual_model (GTK_TREE_VIEW (treeview))); + + chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources); + g_signal_connect (chooser, "response", + G_CALLBACK (chooser_response), builder); +} + +static void +remove_selected_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter child_iter; + GtkTreePath *path; + + g_debug ("remove selected input source"); + + if (get_selected_iter (builder, &model, &iter) == FALSE) + return; + + path = gtk_tree_model_get_path (model, &iter); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_list_store_remove (GTK_LIST_STORE (child_model), &child_iter); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + gtk_tree_path_prev (path); + + set_selected_path (builder, path); + + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_up (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, prev; + GtkTreeIter child_iter, child_prev; + GtkTreePath *path; + + g_debug ("move selected input source up"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + prev = iter; + if (!gtk_tree_model_iter_previous (model, &prev)) + return; + + path = gtk_tree_model_get_path (model, &prev); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_prev, + &prev); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_prev); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_down (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, next; + GtkTreeIter child_iter, child_next; + GtkTreePath *path; + + g_debug ("move selected input source down"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + next = iter; + if (!gtk_tree_model_iter_next (model, &next)) + return; + + path = gtk_tree_model_get_path (model, &next); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_next, + &next); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_next); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +show_selected_layout (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *id; + gchar *kbd_viewer_args; + const gchar *xkb_layout; + const gchar *xkb_variant; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, NULL, NULL, &xkb_layout, &xkb_variant); + + if (!xkb_layout || !xkb_layout[0]) + { + g_warning ("Couldn't find XKB input source '%s'", id); + goto exit; + } + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + xkb_layout = ibus_engine_desc_get_layout (engine_desc); + xkb_variant = ""; + } + else + { + g_warning ("Couldn't find IBus input source '%s'", id); + goto exit; + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + goto exit; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + goto exit; + } + + if (xkb_variant[0]) + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", + xkb_layout, xkb_variant); + else + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", + xkb_layout); + + g_spawn_command_line_async (kbd_viewer_args, NULL); + + g_free (kbd_viewer_args); + exit: + g_free (type); + g_free (id); +} + +static void +show_selected_settings (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + GdkAppLaunchContext *ctx; + GDesktopAppInfo *app_info; + gchar *id; + GError *error = NULL; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + + if (!app_info) + return; + + ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); + gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ()); + + gtk_tree_model_get (model, &iter, ID_COLUMN, &id, -1); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx), + "IBUS_ENGINE_NAME", + id); + g_free (id); + + if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) + { + g_warning ("Failed to launch input source setup: %s", error->message); + g_error_free (error); + } + + g_object_unref (ctx); + g_object_unref (app_info); +} + +static gboolean +go_to_shortcuts (GtkLinkButton *button, + CcRegionPanel *panel) +{ + CcShell *shell; + const gchar *argv[] = { "shortcuts", "Typing", NULL }; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error)) + { + g_warning ("Failed to activate Keyboard panel: %s", error->message); + g_error_free (error); + } + + return TRUE; +} + +static void +input_sources_changed (GSettings *settings, + gchar *key, + GtkBuilder *builder) +{ + GtkWidget *treeview; + GtkTreeModel *store; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeModel *model; + + treeview = WID("active_input_sources"); + store = tree_view_get_actual_model (GTK_TREE_VIEW (treeview)); + + if (get_selected_iter (builder, &model, &iter)) + path = gtk_tree_model_get_path (model, &iter); + else + path = NULL; + + gtk_list_store_clear (GTK_LIST_STORE (store)); + populate_with_active_sources (GTK_LIST_STORE (store)); + + if (path) + { + set_selected_path (builder, path); + gtk_tree_path_free (path); + } +} + +static void +update_shortcut_label (GtkWidget *widget, + const char *value) +{ + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + if (value == NULL || *value == '\0') + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +update_shortcuts (GtkBuilder *builder) +{ + char **previous, **next; + GSettings *settings; + + settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); + + previous = g_settings_get_strv (settings, "switch-input-source-backward"); + next = g_settings_get_strv (settings, "switch-input-source"); + + update_shortcut_label (WID ("prev-source-shortcut-label"), previous[0]); + update_shortcut_label (WID ("next-source-shortcut-label"), next[0]); + + g_strfreev (previous); + g_strfreev (next); +} + +static gboolean +active_sources_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *display_name; + + gtk_tree_model_get (model, iter, NAME_COLUMN, &display_name, -1); + + if (!display_name) + return FALSE; + + g_free (display_name); + + return TRUE; +} + +void +setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *panel) +{ + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkListStore *store; + GtkTreeModel *filtered_store; + GtkTreeSelection *selection; + + /* set up the list of active inputs */ + treeview = WID("active_input_sources"); + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_DESKTOP_APP_INFO); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); + g_settings_delay (input_sources_settings); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) g_object_unref, input_sources_settings); + + if (!xkb_info) + xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + builder, + NULL); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) clear_ibus, NULL); +#endif + + populate_with_active_sources (store); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect_swapped (selection, "changed", + G_CALLBACK (update_button_sensitivity), builder); + + /* Some input source types might have their info loaded + * asynchronously. In that case we don't want to show them + * immediately so we use a filter model on top of the real model + * which mirrors the GSettings key. */ + filtered_store = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered_store), + active_sources_visible_func, + NULL, + NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), filtered_store); + + /* set up the buttons */ + g_signal_connect (WID("input_source_add"), "clicked", + G_CALLBACK (add_input), builder); + g_signal_connect (WID("input_source_remove"), "clicked", + G_CALLBACK (remove_selected_input), builder); + g_signal_connect (WID("input_source_move_up"), "clicked", + G_CALLBACK (move_selected_input_up), builder); + g_signal_connect (WID("input_source_move_down"), "clicked", + G_CALLBACK (move_selected_input_down), builder); + g_signal_connect (WID("input_source_show"), "clicked", + G_CALLBACK (show_selected_layout), builder); + g_signal_connect (WID("input_source_settings"), "clicked", + G_CALLBACK (show_selected_settings), builder); + + /* use an em dash is no shortcut */ + update_shortcuts (builder); + + g_signal_connect (WID("jump-to-shortcuts"), "activate-link", + G_CALLBACK (go_to_shortcuts), panel); + + g_signal_connect (G_OBJECT (input_sources_settings), + "changed::" KEY_INPUT_SOURCES, + G_CALLBACK (input_sources_changed), + builder); + + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-true"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-false"), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + /* because we are in delay-apply mode */ + g_signal_connect_swapped (WID("per-window-radio-true"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); + g_signal_connect_swapped (WID("per-window-radio-false"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); +} + +static void +filter_clear (GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + gpointer user_data) +{ + gtk_entry_set_text (entry, ""); +} + +static gchar **search_pattern_list; + +static void +filter_changed (GtkBuilder *builder) +{ + GtkTreeModelFilter *filtered_model; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreeIter selected_iter; + GtkWidget *filter_entry; + const gchar *pattern; + gchar *upattern; + + filter_entry = WID ("input_source_filter"); + pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry)); + upattern = g_utf8_strup (pattern, -1); + if (!g_strcmp0 (pattern, "")) + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-find-symbolic", + "secondary-icon-activatable", FALSE, + "secondary-icon-sensitive", FALSE, + NULL); + else + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-clear-symbolic", + "secondary-icon-activatable", TRUE, + "secondary-icon-sensitive", TRUE, + NULL); + + if (search_pattern_list != NULL) + g_strfreev (search_pattern_list); + + search_pattern_list = g_strsplit (upattern, " ", -1); + g_free (upattern); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + gtk_tree_model_filter_refilter (filtered_model); + + tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list")); + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model), + &selected_iter); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free (path); + } + else + { + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkBuilder *builder) +{ + gtk_widget_set_sensitive (WID ("ok-button"), + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkBuilder *builder) +{ + GtkWidget *add_button; + GtkWidget *dialog; + + add_button = WID ("ok-button"); + dialog = WID ("input_source_chooser"); + if (gtk_widget_is_sensitive (add_button)) + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +entry_activated (GtkBuilder *builder, + gpointer data) +{ + row_activated (NULL, NULL, NULL, builder); +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name = NULL; + gchar **pattern; + gboolean rv = TRUE; + + if (search_pattern_list == NULL || search_pattern_list[0] == NULL) + return TRUE; + + gtk_tree_model_get (model, iter, + NAME_COLUMN, &name, + -1); + + pattern = search_pattern_list; + do { + gboolean is_pattern_found = FALSE; + gchar *udesc = g_utf8_strup (name, -1); + if (udesc != NULL && g_strstr_len (udesc, -1, *pattern)) + { + is_pattern_found = TRUE; + } + g_free (udesc); + + if (!is_pattern_found) + { + rv = FALSE; + break; + } + + } while (*++pattern != NULL); + + g_free (name); + + return rv; +} + +static GtkWidget * +input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources) +{ + GtkBuilder *builder; + GtkWidget *chooser; + GtkWidget *filtered_list; + GtkWidget *filter_entry; + GtkTreeViewColumn *visible_column; + GtkTreeSelection *selection; + GtkListStore *model; + GtkTreeModelFilter *filtered_model; + GtkTreeIter iter; + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, + GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui", + NULL); + chooser = WID ("input_source_chooser"); + input_chooser = chooser; + g_object_add_weak_pointer (G_OBJECT (chooser), (gpointer *) &input_chooser); + g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref); + + filtered_list = WID ("filtered_input_source_list"); + filter_entry = WID ("input_source_filter"); + + g_object_set_data (G_OBJECT (chooser), + "filtered_input_source_list", filtered_list); + visible_column = + gtk_tree_view_column_new_with_attributes ("Input Sources", + gtk_cell_renderer_text_new (), + "text", NAME_COLUMN, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window); + + gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list), + visible_column); + /* We handle searching ourselves, thank you. */ + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1); + + g_signal_connect_swapped (G_OBJECT (filter_entry), "activate", + G_CALLBACK (entry_activated), builder); + g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text", + G_CALLBACK (filter_changed), builder); + + g_signal_connect (G_OBJECT (filter_entry), "icon-release", + G_CALLBACK (filter_clear), NULL); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + populate_model (model, active_sources); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + NAME_COLUMN, GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (filtered_model, + filter_func, + NULL, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list)); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), builder); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + + g_signal_connect (G_OBJECT (filtered_list), "row-activated", + G_CALLBACK (row_activated), builder); + + gtk_widget_grab_focus (filter_entry); + + gtk_widget_show (chooser); + + return chooser; +} + +static gboolean +input_chooser_get_selected (GtkWidget *dialog, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkWidget *tv; + GtkTreeSelection *selection; + + tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list"); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + + return gtk_tree_selection_get_selected (selection, model, iter); +} diff -Nru gnome-control-center-3.6.3/.pc/git_iconview_columns.patch/shell/cc-shell-category-view.c gnome-control-center-3.6.3/.pc/git_iconview_columns.patch/shell/cc-shell-category-view.c --- gnome-control-center-3.6.3/.pc/git_iconview_columns.patch/shell/cc-shell-category-view.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_iconview_columns.patch/shell/cc-shell-category-view.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2010 Intel, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + +#include "cc-shell-category-view.h" +#include "cc-shell-item-view.h" +#include "cc-shell.h" +#include "cc-shell-model.h" + +G_DEFINE_TYPE (CcShellCategoryView, cc_shell_category_view, GTK_TYPE_FRAME) + +#define SHELL_CATEGORY_VIEW_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SHELL_CATEGORY_VIEW, CcShellCategoryViewPrivate)) + +enum +{ + PROP_NAME = 1, + PROP_MODEL +}; + +struct _CcShellCategoryViewPrivate +{ + gchar *name; + GtkTreeModel *model; + GtkWidget *iconview; +}; + +static void +cc_shell_category_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + CcShellCategoryViewPrivate *priv = CC_SHELL_CATEGORY_VIEW (object)->priv; + + switch (property_id) + { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + + case PROP_MODEL: + g_value_set_object (value, priv->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_shell_category_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + CcShellCategoryViewPrivate *priv = CC_SHELL_CATEGORY_VIEW (object)->priv; + + switch (property_id) + { + case PROP_NAME: + priv->name = g_value_dup_string (value); + break; + + case PROP_MODEL: + priv->model = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_shell_category_view_dispose (GObject *object) +{ + CcShellCategoryViewPrivate *priv = CC_SHELL_CATEGORY_VIEW (object)->priv; + + if (priv->model) + { + g_object_unref (priv->model); + priv->model = NULL; + } + + G_OBJECT_CLASS (cc_shell_category_view_parent_class)->dispose (object); +} + +static void +cc_shell_category_view_finalize (GObject *object) +{ + CcShellCategoryViewPrivate *priv = CC_SHELL_CATEGORY_VIEW (object)->priv; + + if (priv->name) + { + g_free (priv->name); + priv->name = NULL; + } + + G_OBJECT_CLASS (cc_shell_category_view_parent_class)->finalize (object); +} + +static void +cc_shell_category_view_constructed (GObject *object) +{ + CcShellCategoryViewPrivate *priv = CC_SHELL_CATEGORY_VIEW (object)->priv; + GtkWidget *iconview, *vbox; + GtkCellRenderer *renderer; + + iconview = cc_shell_item_view_new (); + gtk_icon_view_set_model (GTK_ICON_VIEW (iconview), priv->model); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (iconview), + renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (iconview), renderer, + "pixbuf", COL_PIXBUF); + + gtk_icon_view_set_text_column (GTK_ICON_VIEW (iconview), COL_NAME); + gtk_icon_view_set_item_width (GTK_ICON_VIEW (iconview), 100); + cc_shell_item_view_update_cells (CC_SHELL_ITEM_VIEW (iconview)); + + /* create the header if required */ + if (priv->name) + { + GtkWidget *label; + PangoAttrList *attrs; + + label = gtk_label_new (priv->name); + attrs = pango_attr_list_new (); + pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); + gtk_label_set_attributes (GTK_LABEL (label), attrs); + pango_attr_list_unref (attrs); + gtk_frame_set_label_widget (GTK_FRAME (object), label); + gtk_widget_show (label); + } + + /* add the iconview to the vbox */ + gtk_box_pack_start (GTK_BOX (vbox), iconview, FALSE, TRUE, 0); + + /* add the main vbox to the view */ + gtk_container_add (GTK_CONTAINER (object), vbox); + gtk_widget_show_all (vbox); + + priv->iconview = iconview; +} + +static void +cc_shell_category_view_class_init (CcShellCategoryViewClass *klass) +{ + GParamSpec *pspec; + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcShellCategoryViewPrivate)); + + object_class->get_property = cc_shell_category_view_get_property; + object_class->set_property = cc_shell_category_view_set_property; + object_class->dispose = cc_shell_category_view_dispose; + object_class->finalize = cc_shell_category_view_finalize; + object_class->constructed = cc_shell_category_view_constructed; + + pspec = g_param_spec_string ("name", + "Name", + "Name of the category", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_NAME, pspec); + + pspec = g_param_spec_object ("model", + "Model", + "Model of the category", + GTK_TYPE_TREE_MODEL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_MODEL, pspec); + +} + +static void +cc_shell_category_view_init (CcShellCategoryView *self) +{ + self->priv = SHELL_CATEGORY_VIEW_PRIVATE (self); + + gtk_frame_set_shadow_type (GTK_FRAME (self), GTK_SHADOW_NONE); +} + +GtkWidget * +cc_shell_category_view_new (const gchar *name, + GtkTreeModel *model) +{ + return g_object_new (CC_TYPE_SHELL_CATEGORY_VIEW, + "name", name, + "model", model, NULL); +} + +CcShellItemView* +cc_shell_category_view_get_item_view (CcShellCategoryView *self) +{ + return (CcShellItemView*) self->priv->iconview; +} diff -Nru gnome-control-center-3.6.3/.pc/git_keyboard_grp_xkb_option.patch/panels/keyboard/cc-keyboard-option.c gnome-control-center-3.6.3/.pc/git_keyboard_grp_xkb_option.patch/panels/keyboard/cc-keyboard-option.c --- gnome-control-center-3.6.3/.pc/git_keyboard_grp_xkb_option.patch/panels/keyboard/cc-keyboard-option.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_keyboard_grp_xkb_option.patch/panels/keyboard/cc-keyboard-option.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. + * + * Written by: Rui Matos + * + * 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, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#include "cc-keyboard-option.h" + +#define CC_TYPE_KEYBOARD_OPTION (cc_keyboard_option_get_type ()) +#define CC_KEYBOARD_OPTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOption)) +#define CC_KEYBOARD_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOptionClass)) +#define CC_IS_KEYBOARD_OPTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_KEYBOARD_OPTION)) +#define CC_IS_KEYBOARD_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_KEYBOARD_OPTION)) +#define CC_KEYBOARD_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOptionClass)) + +#define INPUT_SOURCES_SCHEMA "org.gnome.desktop.input-sources" +#define XKB_OPTIONS_KEY "xkb-options" + +#define XKB_OPTION_GROUP_LVL3 "lv3" +#define XKB_OPTION_GROUP_COMP "Compose key" + +enum +{ + PROP_0, + PROP_GROUP, + PROP_DESCRIPTION +}; + +enum +{ + CHANGED_SIGNAL, + LAST_SIGNAL +}; + +struct _CcKeyboardOption +{ + GObject parent_object; + + gchar *group; + gchar *description; + gchar *current_value; + GtkListStore *store; + + const gchar * const *whitelist; +}; + +typedef struct _CcKeyboardOptionClass CcKeyboardOptionClass; +struct _CcKeyboardOptionClass +{ + GObjectClass parent_class; +}; + +static guint keyboard_option_signals[LAST_SIGNAL] = { 0 }; + +static GnomeXkbInfo *xkb_info = NULL; +static GSettings *input_sources_settings = NULL; +static gchar **current_xkb_options = NULL; + +static const gchar *xkb_option_lvl3_whitelist[] = { + "lv3:switch", + "lv3:menu_switch", + "lv3:rwin_switch", + "lv3:lalt_switch", + "lv3:ralt_switch", + "lv3:caps_switch", + NULL +}; + +static const gchar *xkb_option_comp_whitelist[] = { + "compose:ralt", + "compose:rwin", + "compose:menu", + "compose:lctrl", + "compose:rctrl", + "compose:caps", + NULL +}; + +static GList *objects_list = NULL; + +GType cc_keyboard_option_get_type (void); + +G_DEFINE_TYPE (CcKeyboardOption, cc_keyboard_option, G_TYPE_OBJECT); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +static void +reload_setting (CcKeyboardOption *self) +{ + gchar **iter; + + for (iter = current_xkb_options; *iter; ++iter) + if (strv_contains (self->whitelist, *iter)) + { + if (g_strcmp0 (self->current_value, *iter) != 0) + { + g_free (self->current_value); + self->current_value = g_strdup (*iter); + g_signal_emit (self, keyboard_option_signals[CHANGED_SIGNAL], 0); + } + break; + } + + if (*iter == NULL && self->current_value != NULL) + { + g_clear_pointer (&self->current_value, g_free); + g_signal_emit (self, keyboard_option_signals[CHANGED_SIGNAL], 0); + } +} + +static void +xkb_options_changed (GSettings *settings, + gchar *key, + gpointer data) +{ + GList *l; + + g_strfreev (current_xkb_options); + current_xkb_options = g_settings_get_strv (settings, key); + + for (l = objects_list; l; l = l->next) + reload_setting (CC_KEYBOARD_OPTION (l->data)); +} + +static void +cc_keyboard_option_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CcKeyboardOption *self; + + self = CC_KEYBOARD_OPTION (object); + + switch (prop_id) + { + case PROP_GROUP: + g_value_set_string (value, self->group); + break; + case PROP_DESCRIPTION: + g_value_set_string (value, self->description); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_keyboard_option_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CcKeyboardOption *self; + + self = CC_KEYBOARD_OPTION (object); + + switch (prop_id) + { + case PROP_GROUP: + self->group = g_value_dup_string (value); + break; + case PROP_DESCRIPTION: + self->description = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_keyboard_option_init (CcKeyboardOption *self) +{ +} + +static void +cc_keyboard_option_finalize (GObject *object) +{ + CcKeyboardOption *self = CC_KEYBOARD_OPTION (object); + + g_clear_pointer (&self->group, g_free); + g_clear_pointer (&self->description, g_free); + g_clear_pointer (&self->current_value, g_free); + g_clear_object (&self->store); + + G_OBJECT_CLASS (cc_keyboard_option_parent_class)->finalize (object); +} + +static void +cc_keyboard_option_constructed (GObject *object) +{ + GtkTreeIter iter; + GList *options, *l; + gchar *option_id; + CcKeyboardOption *self = CC_KEYBOARD_OPTION (object); + + G_OBJECT_CLASS (cc_keyboard_option_parent_class)->constructed (object); + + if (g_str_equal (self->group, XKB_OPTION_GROUP_LVL3)) + self->whitelist = xkb_option_lvl3_whitelist; + else if (g_str_equal (self->group, XKB_OPTION_GROUP_COMP)) + self->whitelist = xkb_option_comp_whitelist; + else + g_assert_not_reached (); + + self->store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + gtk_list_store_append (self->store, &iter); + gtk_list_store_set (self->store, &iter, + XKB_OPTION_DESCRIPTION_COLUMN, _("Disabled"), + XKB_OPTION_ID_COLUMN, NULL, + -1); + options = gnome_xkb_info_get_options_for_group (xkb_info, self->group); + for (l = options; l; l = l->next) + { + option_id = l->data; + if (strv_contains (self->whitelist, option_id)) + { + gtk_list_store_append (self->store, &iter); + gtk_list_store_set (self->store, &iter, + XKB_OPTION_DESCRIPTION_COLUMN, + gnome_xkb_info_description_for_option (xkb_info, self->group, option_id), + XKB_OPTION_ID_COLUMN, + option_id, + -1); + } + } + g_list_free (options); + + reload_setting (self); +} + +static void +cc_keyboard_option_class_init (CcKeyboardOptionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = cc_keyboard_option_get_property; + gobject_class->set_property = cc_keyboard_option_set_property; + gobject_class->finalize = cc_keyboard_option_finalize; + gobject_class->constructed = cc_keyboard_option_constructed; + + g_object_class_install_property (gobject_class, + PROP_GROUP, + g_param_spec_string ("group", + "group", + "xkb option group identifier", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); + g_object_class_install_property (gobject_class, + PROP_DESCRIPTION, + g_param_spec_string ("description", + "description", + "translated option description", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + keyboard_option_signals[CHANGED_SIGNAL] = g_signal_new ("changed", + CC_TYPE_KEYBOARD_OPTION, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 0); +} + +GList * +cc_keyboard_option_get_all (void) +{ + if (objects_list) + return objects_list; + + xkb_info = gnome_xkb_info_new (); + + input_sources_settings = g_settings_new (INPUT_SOURCES_SCHEMA); + + g_signal_connect (input_sources_settings, "changed::" XKB_OPTIONS_KEY, + G_CALLBACK (xkb_options_changed), NULL); + + xkb_options_changed (input_sources_settings, XKB_OPTIONS_KEY, NULL); + + objects_list = g_list_prepend (objects_list, + g_object_new (CC_TYPE_KEYBOARD_OPTION, + "group", XKB_OPTION_GROUP_LVL3, + "description", _("Alternative Characters Key"), + NULL)); + objects_list = g_list_prepend (objects_list, + g_object_new (CC_TYPE_KEYBOARD_OPTION, + "group", XKB_OPTION_GROUP_COMP, + "description", _("Compose Key"), + NULL)); + return objects_list; +} + +const gchar * +cc_keyboard_option_get_description (CcKeyboardOption *self) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL); + + return self->description; +} + +GtkListStore * +cc_keyboard_option_get_store (CcKeyboardOption *self) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL); + + return self->store; +} + +const gchar * +cc_keyboard_option_get_current_value_description (CcKeyboardOption *self) +{ + g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL); + + if (!self->current_value) + return _("Disabled"); + + return gnome_xkb_info_description_for_option (xkb_info, self->group, self->current_value); +} + +static void +remove_value (const gchar *value) +{ + gchar **p; + + for (p = current_xkb_options; *p; ++p) + if (g_str_equal (*p, value)) + { + g_free (*p); + break; + } + + for (++p; *p; ++p) + *(p - 1) = *p; + + *(p - 1) = NULL; +} + +static void +add_value (const gchar *value) +{ + gchar **new_xkb_options; + gchar **a, **b; + + new_xkb_options = g_new0 (gchar *, g_strv_length (current_xkb_options) + 2); + + a = new_xkb_options; + for (b = current_xkb_options; *b; ++a, ++b) + *a = g_strdup (*b); + + *a = g_strdup (value); + + g_strfreev (current_xkb_options); + current_xkb_options = new_xkb_options; +} + +static void +replace_value (const gchar *old, + const gchar *new) +{ + gchar **iter; + + if (g_str_equal (old, new)) + return; + + for (iter = current_xkb_options; *iter; ++iter) + if (g_str_equal (*iter, old)) + { + g_free (*iter); + *iter = g_strdup (new); + break; + } +} + +void +cc_keyboard_option_set_selection (CcKeyboardOption *self, + GtkTreeIter *iter) +{ + gchar *new_value = NULL; + + g_return_if_fail (CC_IS_KEYBOARD_OPTION (self)); + + gtk_tree_model_get (GTK_TREE_MODEL (self->store), iter, + XKB_OPTION_ID_COLUMN, &new_value, + -1); + + if (!new_value) + { + if (self->current_value) + remove_value (self->current_value); + } + else + { + if (self->current_value) + replace_value (self->current_value, new_value); + else + add_value (new_value); + } + + g_settings_set_strv (input_sources_settings, XKB_OPTIONS_KEY, + (const gchar * const *) current_xkb_options); + + g_free (new_value); +} + +void +cc_keyboard_option_clear_all (void) +{ + GList *l; + + for (l = objects_list; l; l = l->next) + g_object_unref (l->data); + + g_clear_pointer (&objects_list, g_list_free); + g_clear_pointer (¤t_xkb_options, g_strfreev); + g_clear_object (&input_sources_settings); + g_clear_object (&xkb_info); +} diff -Nru gnome-control-center-3.6.3/.pc/git_keyboard_update_input_switch.patch/panels/keyboard/01-input-sources.xml.in gnome-control-center-3.6.3/.pc/git_keyboard_update_input_switch.patch/panels/keyboard/01-input-sources.xml.in --- gnome-control-center-3.6.3/.pc/git_keyboard_update_input_switch.patch/panels/keyboard/01-input-sources.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_keyboard_update_input_switch.patch/panels/keyboard/01-input-sources.xml.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,12 @@ + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/configure.ac gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/configure.ac --- gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,551 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +shell/libgnome-control-center.pc +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/bluetooth-properties.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/cc-display-panel.c gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/cc-display-panel.c --- gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/cc-display-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/cc-display-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,2989 @@ +/* + * Copyright (C) 2007, 2008 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Soren Sandmann + * + */ + +#include +#include +#include +#include + +#include "cc-display-panel.h" + +#include +#include "scrollarea.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include +#include +#include +#include +#include +#include + +CC_PANEL_REGISTER (CcDisplayPanel, cc_display_panel) + +#define DISPLAY_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DISPLAY_PANEL, CcDisplayPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +#define TOP_BAR_HEIGHT 10 + +#define CLOCK_SCHEMA "org.gnome.desktop.interface" +#define CLOCK_FORMAT_KEY "clock-format" + +/* The minimum supported size for the panel, see: + * http://live.gnome.org/Design/SystemSettings */ +#define MINIMUM_WIDTH 675 +#define MINIMUM_HEIGHT 530 + +#define UNITY_GSETTINGS_SCHEMA "org.compiz.unityshell" +#define UNITY_GSETTINGS_PATH "/org/compiz/profiles/unity/plugins/unityshell/" +#define UNITY_LAUNCHER_ALL_MONITORS_KEY "num-launchers" +#define UNITY_STICKY_EDGE_KEY "launcher-capture-mouse" +#define UNITY2D_GSETTINGS_MAIN "com.canonical.Unity2d" +#define UNITY2D_GSETTINGS_LAUNCHER "com.canonical.Unity2d.Launcher" + +enum { + TEXT_COL, + WIDTH_COL, + HEIGHT_COL, + RATE_COL, + SORT_COL, + ROTATION_COL, + NUM_COLS +}; + +struct _CcDisplayPanelPrivate +{ + GnomeRRScreen *screen; + GnomeRRConfig *current_configuration; + GnomeRRLabeler *labeler; + GnomeRROutputInfo *current_output; + + GSettings *clock_settings; + GSettings *unity_settings; + GSettings *unity2d_settings_main; + GSettings *unity2d_settings_launcher; + GtkBuilder *builder; + guint focus_id; + + GtkWidget *panel; + GtkWidget *current_monitor_event_box; + GtkWidget *current_monitor_label; + GtkWidget *monitor_switch; + GtkListStore *resolution_store; + GtkWidget *resolution_combo; + GtkWidget *rotation_combo; + GtkWidget *clone_checkbox; + GtkWidget *clone_label; + GtkWidget *show_icon_checkbox; + + /* We store the event timestamp when the Apply button is clicked */ + guint32 apply_button_clicked_timestamp; + + GtkWidget *area; + gboolean ignore_gui_changes; + gboolean dragging_top_bar; + + /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */ + GDBusProxy *proxy; +}; + +typedef struct +{ + int grab_x; + int grab_y; + int output_x; + int output_y; +} GrabInfo; + +static void rebuild_gui (CcDisplayPanel *self); +static void on_clone_changed (GtkWidget *box, gpointer data); +static gboolean output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config); +static void select_current_output_from_dialog_position (CcDisplayPanel *self); +static void monitor_switch_active_cb (GObject *object, GParamSpec *pspec, gpointer data); +static void get_geometry (GnomeRROutputInfo *output, int *w, int *h); +static void apply_configuration_returned_cb (GObject *proxy, GAsyncResult *res, gpointer data); +static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height); +static gboolean output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height); +static char *make_resolution_string (int width, int height); +static GObject *cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties); +static void on_screen_changed (GnomeRRScreen *scr, gpointer data); +static void refresh_unity_launcher_placement (CcDisplayPanel *self); +static gboolean unity_launcher_on_all_monitors (GSettings *settings); + +static void +cc_display_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_display_panel_dispose (GObject *object) +{ + G_OBJECT_CLASS (cc_display_panel_parent_class)->dispose (object); +} + +static void +cc_display_panel_finalize (GObject *object) +{ + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + + self = CC_DISPLAY_PANEL (object); + + g_signal_handlers_disconnect_by_func (self->priv->screen, on_screen_changed, self); + g_object_unref (self->priv->screen); + g_object_unref (self->priv->builder); + + if (self->priv->clock_settings != NULL) + g_object_unref (self->priv->clock_settings); + + if (self->priv->unity2d_settings_main != NULL) + g_object_unref (self->priv->unity2d_settings_main); + if (self->priv->unity2d_settings_launcher != NULL) + g_object_unref (self->priv->unity2d_settings_launcher); + if (self->priv->unity_settings != NULL) + g_object_unref (self->priv->unity_settings); + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (shell != NULL) + { + toplevel = cc_shell_get_toplevel (shell); + if (toplevel != NULL) + g_signal_handler_disconnect (G_OBJECT (toplevel), + self->priv->focus_id); + } + + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + + G_OBJECT_CLASS (cc_display_panel_parent_class)->finalize (object); +} + +static const char * +cc_display_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; +} + +static void +cc_display_panel_class_init (CcDisplayPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcDisplayPanelPrivate)); + + panel_class->get_help_uri = cc_display_panel_get_help_uri; + + object_class->constructor = cc_display_panel_constructor; + object_class->get_property = cc_display_panel_get_property; + object_class->set_property = cc_display_panel_set_property; + object_class->dispose = cc_display_panel_dispose; + object_class->finalize = cc_display_panel_finalize; +} + +static void +error_message (CcDisplayPanel *self, const char *primary_text, const char *secondary_text) +{ + GtkWidget *toplevel; + GtkWidget *dialog; + + if (self && self->priv->panel) + toplevel = gtk_widget_get_toplevel (self->priv->panel); + else + toplevel = NULL; + + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + + if (secondary_text) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static gboolean +is_unity_session (void) +{ + return (g_strcmp0 (g_getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0); +} + +static gboolean +should_show_resolution (gint output_width, + gint output_height, + gint width, + gint height) +{ + if (width >= MIN (output_width, MINIMUM_WIDTH) && + height >= MIN (output_height, MINIMUM_HEIGHT)) + { + return TRUE; + } + return FALSE; +} + +static void +on_screen_changed (GnomeRRScreen *scr, + gpointer data) +{ + GnomeRRConfig *current; + CcDisplayPanel *self = data; + + current = gnome_rr_config_new_current (self->priv->screen, NULL); + gnome_rr_config_ensure_primary (current); + + if (self->priv->current_configuration) + g_object_unref (self->priv->current_configuration); + + self->priv->current_configuration = current; + self->priv->current_output = NULL; + + if (self->priv->labeler) { + gnome_rr_labeler_hide (self->priv->labeler); + g_object_unref (self->priv->labeler); + } + + self->priv->labeler = gnome_rr_labeler_new (self->priv->current_configuration); + if (gtk_widget_has_focus (self->priv->panel)) + gnome_rr_labeler_show (self->priv->labeler); + + select_current_output_from_dialog_position (self); + + if (is_unity_session ()) + refresh_unity_launcher_placement (self); +} + +static void +on_viewport_changed (FooScrollArea *scroll_area, + GdkRectangle *old_viewport, + GdkRectangle *new_viewport) +{ + foo_scroll_area_set_size (scroll_area, + new_viewport->width, + new_viewport->height); + + foo_scroll_area_invalidate (scroll_area); +} + +static void +layout_set_font (PangoLayout *layout, const char *font) +{ + PangoFontDescription *desc = + pango_font_description_from_string (font); + + if (desc) + { + pango_layout_set_font_description (layout, desc); + + pango_font_description_free (desc); + } +} + +static void +clear_combo (GtkWidget *widget) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + GtkListStore *store = GTK_LIST_STORE (model); + + gtk_list_store_clear (store); +} + +typedef struct +{ + const char *text; + gboolean found; + GtkTreeIter iter; +} ForeachInfo; + +static gboolean +foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + ForeachInfo *info = data; + char *text = NULL; + + gtk_tree_model_get (model, iter, TEXT_COL, &text, -1); + + g_assert (text != NULL); + + if (strcmp (info->text, text) == 0) + { + info->found = TRUE; + info->iter = *iter; + return TRUE; + } + + return FALSE; +} + +static void +add_key (GtkTreeModel *model, + const char *text, + gboolean preferred, + int width, int height, int rate, + GnomeRRRotation rotation) +{ + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + { + GtkTreeIter iter; + g_debug ("adding %s with rate %d Hz", text, rate); + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, -1, + TEXT_COL, text, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + SORT_COL, width * 10000 + height, + ROTATION_COL, rotation, + -1); + return; + } + + /* Look, the preferred output, replace the old one */ + if (preferred) + { + g_debug ("replacing %s with rate %d Hz (preferred mode)", text, rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + + { + int old_rate; + + gtk_tree_model_get (model, &info.iter, + RATE_COL, &old_rate, + -1); + + /* Higher refresh rate */ + if (rate > old_rate) + { + g_debug ("replacing %s with rate %d Hz (old rate: %d)", text, rate, old_rate); + gtk_list_store_set (GTK_LIST_STORE (model), &info.iter, + RATE_COL, rate, + -1); + return; + } + } + + g_debug ("not adding %s with rate %d Hz (higher rate already there)", text, rate); +} + +static void +add_mode (CcDisplayPanel *self, + GnomeRRMode *mode, + gint output_width, + gint output_height, + guint preferred_id) +{ + int width, height, rate; + + width = gnome_rr_mode_get_width (mode); + height = gnome_rr_mode_get_height (mode); + rate = gnome_rr_mode_get_freq (mode); + + if (should_show_resolution (output_width, output_height, width, height)) + { + char *text; + gboolean preferred; + + preferred = (gnome_rr_mode_get_id (mode) == preferred_id); + text = make_resolution_string (width, height); + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->resolution_combo)), + text, preferred, width, height, rate, -1); + g_free (text); + } +} + + + +static gboolean +combo_select (GtkWidget *widget, const char *text) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkTreeModel *model = gtk_combo_box_get_model (box); + ForeachInfo info; + + info.text = text; + info.found = FALSE; + + gtk_tree_model_foreach (model, foreach, &info); + + if (!info.found) + return FALSE; + + gtk_combo_box_set_active_iter (box, &info.iter); + return TRUE; +} + +static GnomeRRMode ** +get_current_modes (CcDisplayPanel *self) +{ + GnomeRROutput *output; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + return gnome_rr_screen_list_clone_modes (self->priv->screen); + } + else + { + if (!self->priv->current_output) + return NULL; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + + if (!output) + return NULL; + + return gnome_rr_output_list_modes (output); + } +} + +static void +rebuild_rotation_combo (CcDisplayPanel *self) +{ + typedef struct + { + GnomeRRRotation rotation; + const char * name; + } RotationInfo; + static const RotationInfo rotations[] = { + { GNOME_RR_ROTATION_0, NC_("display panel, rotation", "Normal") }, + { GNOME_RR_ROTATION_90, NC_("display panel, rotation", "Counterclockwise") }, + { GNOME_RR_ROTATION_270, NC_("display panel, rotation", "Clockwise") }, + { GNOME_RR_ROTATION_180, NC_("display panel, rotation", "180 Degrees") }, + }; + const char *selection; + GnomeRRRotation current; + int i; + + clear_combo (self->priv->rotation_combo); + + gtk_widget_set_sensitive (self->priv->rotation_combo, + self->priv->current_output && gnome_rr_output_info_is_active (self->priv->current_output)); + + if (!self->priv->current_output) + return; + + current = gnome_rr_output_info_get_rotation (self->priv->current_output); + + selection = NULL; + for (i = 0; i < G_N_ELEMENTS (rotations); ++i) + { + const RotationInfo *info = &(rotations[i]); + + gnome_rr_output_info_set_rotation (self->priv->current_output, info->rotation); + + /* NULL-GError --- FIXME: we should say why this rotation is not available! */ + if (gnome_rr_config_applicable (self->priv->current_configuration, self->priv->screen, NULL)) + { + add_key (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->rotation_combo)), g_dpgettext2 (NULL, "display panel, rotation", info->name), FALSE, 0, 0, 0, info->rotation); + + if (info->rotation == current) + selection = g_dpgettext2 (NULL, "display panel, rotation", info->name); + } + } + + gnome_rr_output_info_set_rotation (self->priv->current_output, current); + + if (!(selection && combo_select (self->priv->rotation_combo, selection))) + gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->rotation_combo), 0); +} + +static int +count_active_outputs (CcDisplayPanel *self) +{ + int i, count = 0; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_active (outputs[i])) + count++; + } + + return count; +} + +#if 0 +static int +count_all_outputs (GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) + ; + + return i; +} +#endif + +/* Computes whether "Mirror displays" (clone mode) is supported based on these criteria: + * + * 1. There is an available size for cloning. + * + * 2. There are 2 or more connected outputs that support that size. + */ +static gboolean +mirror_screens_is_supported (CcDisplayPanel *self) +{ + int clone_width, clone_height; + gboolean have_clone_size; + gboolean mirror_is_supported; + + mirror_is_supported = FALSE; + + have_clone_size = get_clone_size (self->priv->screen, &clone_width, &clone_height); + + if (have_clone_size) { + int i; + int num_outputs_with_clone_size; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + num_outputs_with_clone_size = 0; + + for (i = 0; outputs[i] != NULL; i++) + { + /* We count the connected outputs that support the clone size. It + * doesn't matter if those outputs aren't actually On currently; we + * will turn them on in on_clone_changed(). + */ + if (gnome_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (self, outputs[i], clone_width, clone_height)) + num_outputs_with_clone_size++; + } + + if (num_outputs_with_clone_size >= 2) + mirror_is_supported = TRUE; + } + + return mirror_is_supported; +} + +static void +rebuild_mirror_screens (CcDisplayPanel *self) +{ + gboolean mirror_is_active; + gboolean mirror_is_supported; + + g_signal_handlers_block_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); + + mirror_is_active = self->priv->current_configuration && gnome_rr_config_get_clone (self->priv->current_configuration); + + /* If mirror_is_active, then it *must* be possible to turn mirroring off */ + mirror_is_supported = mirror_is_active || mirror_screens_is_supported (self); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox), mirror_is_active); + gtk_widget_set_sensitive (self->priv->clone_checkbox, mirror_is_supported); + gtk_widget_set_sensitive (self->priv->clone_label, mirror_is_supported); + + /* set inactive the launcher placement choice */ + gtk_widget_set_sensitive (WID ("launcher_placement_combo"), !mirror_is_active); + gtk_widget_set_sensitive (WID ("stickyedge_switch"), !mirror_is_active); + + g_signal_handlers_unblock_by_func (self->priv->clone_checkbox, G_CALLBACK (on_clone_changed), self); +} + +static char * +mirror_monitor_name (void) +{ + /* Keep this string in sync with gnome-desktop/libgnome-desktop/gnome-rr-labeler.c */ + + /* Translators: this is the feature where what you see on your laptop's + * screen is the same as your external projector. Here, "Mirrored" is being + * used as an adjective. For example, the Spanish translation could be + * "Pantallas en Espejo". + */ + return g_strdup (_("Mirrored Displays")); +} + +static void +rebuild_current_monitor_label (CcDisplayPanel *self) +{ + char *str, *tmp; + GdkRGBA color; + gboolean use_color; + + if (self->priv->current_output) + { + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + tmp = mirror_monitor_name (); + else + tmp = g_strdup (gnome_rr_output_info_get_display_name (self->priv->current_output)); + + str = g_strdup_printf ("%s", tmp); + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, self->priv->current_output, &color); + use_color = TRUE; + g_free (tmp); + } + else + { + str = g_strdup_printf ("%s", _("Monitor")); + use_color = FALSE; + } + + gtk_label_set_markup (GTK_LABEL (self->priv->current_monitor_label), str); + g_free (str); + + if (use_color) + { + GdkRGBA black = { 0, 0, 0, 1.0 }; + + gtk_widget_override_background_color (self->priv->current_monitor_event_box, + gtk_widget_get_state_flags (self->priv->current_monitor_event_box), + &color); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + &black); + } + else + { + /* Remove any modifications we did on the label's color */ + gtk_widget_override_color (self->priv->current_monitor_label, + gtk_widget_get_state_flags (self->priv->current_monitor_label), + NULL); + } + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (self->priv->current_monitor_event_box), use_color); +} + +static void +rebuild_on_off_radios (CcDisplayPanel *self) +{ + gboolean sensitive; + gboolean on_active; + + g_signal_handlers_block_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); + + sensitive = FALSE; + on_active = FALSE; + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && self->priv->current_output) + { + if (count_active_outputs (self) > 1 || !gnome_rr_output_info_is_active (self->priv->current_output)) + sensitive = TRUE; + else + sensitive = FALSE; + + on_active = gnome_rr_output_info_is_active (self->priv->current_output); + } + + gtk_widget_set_sensitive (self->priv->monitor_switch, sensitive); + + gtk_switch_set_active (GTK_SWITCH (self->priv->monitor_switch), on_active); + + g_signal_handlers_unblock_by_func (self->priv->monitor_switch, G_CALLBACK (monitor_switch_active_cb), self); +} + +static char * +make_resolution_string (int width, int height) +{ + int ratio; + const char *aspect = NULL; + + if (width && height) { + if (width > height) + ratio = width * 10 / height; + else + ratio = height * 10 / width; + + switch (ratio) { + case 13: + aspect = "4:3"; + break; + case 16: + aspect = "16:10"; + break; + case 17: + aspect = "16:9"; + break; + case 23: + aspect = "21:9"; + break; + case 12: + aspect = "5:4"; + break; + /* This catches 1.5625 as well (1600x1024) when maybe it shouldn't. */ + case 15: + aspect = "3:2"; + break; + case 18: + aspect = "9:5"; + break; + case 10: + aspect = "1:1"; + break; + } + } + + if (aspect != NULL) + return g_strdup_printf (_("%d x %d (%s)"), width, height, aspect); + else + return g_strdup_printf (_("%d x %d"), width, height); +} + +static void +find_best_mode (GnomeRRMode **modes, int *out_width, int *out_height) +{ + int i; + + *out_width = 0; + *out_height = 0; + + for (i = 0; modes[i] != NULL; i++) + { + int w, h; + + w = gnome_rr_mode_get_width (modes[i]); + h = gnome_rr_mode_get_height (modes[i]); + + if (w * h > *out_width * *out_height) + { + *out_width = w; + *out_height = h; + } + } +} + +static void +rebuild_resolution_combo (CcDisplayPanel *self) +{ + int i; + GnomeRRMode **modes; + GnomeRRMode *mode; + char *current; + int output_width, output_height; + guint32 preferred_id; + GnomeRROutput *output; + + clear_combo (self->priv->resolution_combo); + + if (!(modes = get_current_modes (self)) + || !self->priv->current_output + || !gnome_rr_output_info_is_active (self->priv->current_output)) + { + gtk_widget_set_sensitive (self->priv->resolution_combo, FALSE); + return; + } + + g_assert (self->priv->current_output != NULL); + + gnome_rr_output_info_get_geometry (self->priv->current_output, NULL, NULL, &output_width, &output_height); + g_assert (output_width != 0 && output_height != 0); + + gtk_widget_set_sensitive (self->priv->resolution_combo, TRUE); + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, + gnome_rr_output_info_get_name (self->priv->current_output)); + mode = gnome_rr_output_get_preferred_mode (output); + preferred_id = gnome_rr_mode_get_id (mode); + + for (i = 0; modes[i] != NULL; ++i) + add_mode (self, modes[i], output_width, output_height, preferred_id); + + /* And force the preferred mode in the drop-down (when not in clone mode) + * https://bugzilla.gnome.org/show_bug.cgi?id=680969 */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration)) + add_mode (self, mode, output_width, output_height, preferred_id); + + current = make_resolution_string (output_width, output_height); + + if (!combo_select (self->priv->resolution_combo, current)) + { + int best_w, best_h; + char *str; + + find_best_mode (modes, &best_w, &best_h); + str = make_resolution_string (best_w, best_h); + combo_select (self->priv->resolution_combo, str); + g_free (str); + } + + g_free (current); +} + +static void +rebuild_gui (CcDisplayPanel *self) +{ + /* We would break spectacularly if we recursed, so + * just assert if that happens + */ + g_assert (self->priv->ignore_gui_changes == FALSE); + + self->priv->ignore_gui_changes = TRUE; + + rebuild_mirror_screens (self); + rebuild_current_monitor_label (self); + rebuild_on_off_radios (self); + rebuild_resolution_combo (self); + rebuild_rotation_combo (self); + refresh_unity_launcher_placement (self); + + self->priv->ignore_gui_changes = FALSE; +} + +static gboolean +get_mode (GtkWidget *widget, int *width, int *height, int *rate, GnomeRRRotation *rot) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkComboBox *box = GTK_COMBO_BOX (widget); + int dummy; + + if (!gtk_combo_box_get_active_iter (box, &iter)) + return FALSE; + + if (!width) + width = &dummy; + + if (!height) + height = &dummy; + + if (!rate) + rate = &dummy; + + if (!rot) + rot = (GnomeRRRotation *)&dummy; + + model = gtk_combo_box_get_model (box); + gtk_tree_model_get (model, &iter, + WIDTH_COL, width, + HEIGHT_COL, height, + RATE_COL, rate, + ROTATION_COL, rot, + -1); + + return TRUE; + +} + +static void +on_rotation_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + GnomeRRRotation rotation; + + if (!self->priv->current_output) + return; + + if (get_mode (self->priv->rotation_combo, NULL, NULL, NULL, &rotation)) + gnome_rr_output_info_set_rotation (self->priv->current_output, rotation); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +select_resolution_for_current_output (CcDisplayPanel *self) +{ + GnomeRRMode **modes; + int width, height; + int x,y; + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, NULL, NULL); + + width = gnome_rr_output_info_get_preferred_width (self->priv->current_output); + height = gnome_rr_output_info_get_preferred_height (self->priv->current_output); + + if (width != 0 && height != 0) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + return; + } + + modes = get_current_modes (self); + if (!modes) + return; + + find_best_mode (modes, &width, &height); + + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); +} + +static void +monitor_switch_active_cb (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + CcDisplayPanel *self = data; + gboolean value; + + if (!self->priv->current_output) + return; + + value = gtk_switch_get_active (GTK_SWITCH (object)); + + if (value) + { + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + select_resolution_for_current_output (self); + } + else + { + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + } + + rebuild_gui (self); + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +realign_outputs_after_resolution_change (CcDisplayPanel *self, GnomeRROutputInfo *output_that_changed, int old_width, int old_height) +{ + /* We find the outputs that were below or to the right of the output that + * changed, and realign them; we also do that for outputs that shared the + * right/bottom edges with the output that changed. The outputs that are + * above or to the left of that output don't need to change. + */ + + int i; + int old_right_edge, old_bottom_edge; + int dx, dy; + int x, y, width, height; + GnomeRROutputInfo **outputs; + + g_assert (self->priv->current_configuration != NULL); + + gnome_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height); + + if (width == old_width && height == old_height) + return; + + old_right_edge = x + old_width; + old_bottom_edge = y + old_height; + + dx = width - old_width; + dy = height - old_height; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; i++) + { + int output_x, output_y; + int output_width, output_height; + + if (outputs[i] == output_that_changed || !gnome_rr_output_info_is_connected (outputs[i])) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (output_x >= old_right_edge) + output_x += dx; + else if (output_x + output_width == old_right_edge) + output_x = x + width - output_width; + + if (output_y >= old_bottom_edge) + output_y += dy; + else if (output_y + output_height == old_bottom_edge) + output_y = y + height - output_height; + + gnome_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height); + } +} + +static void +on_resolution_changed (GtkComboBox *box, gpointer data) +{ + CcDisplayPanel *self = data; + int old_width, old_height; + int x,y; + int width; + int height; + + if (!self->priv->current_output) + return; + + gnome_rr_output_info_get_geometry (self->priv->current_output, &x, &y, &old_width, &old_height); + + if (get_mode (self->priv->resolution_combo, &width, &height, NULL, NULL)) + { + gnome_rr_output_info_set_geometry (self->priv->current_output, x, y, width, height); + + if (width == 0 || height == 0) + gnome_rr_output_info_set_active (self->priv->current_output, FALSE); + else + gnome_rr_output_info_set_active (self->priv->current_output, TRUE); + } + + realign_outputs_after_resolution_change (self, self->priv->current_output, old_width, old_height); + + rebuild_rotation_combo (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); +} + +static void +lay_out_outputs_horizontally (CcDisplayPanel *self) +{ + int i; + int x; + GnomeRROutputInfo **outputs; + + /* Lay out all the monitors horizontally when "mirror screens" is turned + * off, to avoid having all of them overlapped initially. We put the + * outputs turned off on the right-hand side. + */ + + x = 0; + + /* First pass, all "on" outputs */ + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + + /* Second pass, all the black screens */ + + for (i = 0; outputs[i]; ++i) + { + int width, height; + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + { + gnome_rr_output_info_get_geometry (outputs[i], NULL, NULL, &width, &height); + gnome_rr_output_info_set_geometry (outputs[i], x, 0, width, height); + x += width; + } + } + +} + +/* FIXME: this function is copied from gnome-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c. + * Do we need to put this function in gnome-desktop for public use? + */ +static gboolean +get_clone_size (GnomeRRScreen *screen, int *width, int *height) +{ + GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); + int best_w, best_h; + int i; + + best_w = 0; + best_h = 0; + + for (i = 0; modes[i] != NULL; ++i) { + GnomeRRMode *mode = modes[i]; + int w, h; + + w = gnome_rr_mode_get_width (mode); + h = gnome_rr_mode_get_height (mode); + + if (w * h > best_w * best_h) { + best_w = w; + best_h = h; + } + } + + if (best_w > 0 && best_h > 0) { + if (width) + *width = best_w; + if (height) + *height = best_h; + + return TRUE; + } + + return FALSE; +} + +static gboolean +output_info_supports_mode (CcDisplayPanel *self, GnomeRROutputInfo *info, int width, int height) +{ + GnomeRROutput *output; + GnomeRRMode **modes; + int i; + + if (!gnome_rr_output_info_is_connected (info)) + return FALSE; + + output = gnome_rr_screen_get_output_by_name (self->priv->screen, gnome_rr_output_info_get_name (info)); + if (!output) + return FALSE; + + modes = gnome_rr_output_list_modes (output); + + for (i = 0; modes[i]; i++) { + if (gnome_rr_mode_get_width (modes[i]) == width + && gnome_rr_mode_get_height (modes[i]) == height) + return TRUE; + } + + return FALSE; +} + +static void +on_clone_changed (GtkWidget *box, gpointer data) +{ + CcDisplayPanel *self = data; + + gnome_rr_config_set_clone (self->priv->current_configuration, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->clone_checkbox))); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + { + int i; + int width, height; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + self->priv->current_output = outputs[i]; + break; + } + } + + /* Turn on all the connected screens that support the best clone mode. + * The user may hit "Mirror displays", but he shouldn't have to turn on + * all the required outputs as well. + */ + + get_clone_size (self->priv->screen, &width, &height); + + for (i = 0; outputs[i]; i++) { + int x, y; + if (output_info_supports_mode (self, outputs[i], width, height)) { + gnome_rr_output_info_set_active (outputs[i], TRUE); + gnome_rr_output_info_get_geometry (outputs[i], &x, &y, NULL, NULL); + gnome_rr_output_info_set_geometry (outputs[i], x, y, width, height); + } + } + } + else + { + if (output_overlaps (self->priv->current_output, self->priv->current_configuration)) + lay_out_outputs_horizontally (self); + } + + rebuild_gui (self); +} + +static void +apply_rotation_to_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + GnomeRRRotation rotation; + + rotation = gnome_rr_output_info_get_rotation (output); + if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270)) + { + int tmp; + tmp = *h; + *h = *w; + *w = tmp; + } +} + +static void +get_geometry (GnomeRROutputInfo *output, int *w, int *h) +{ + if (gnome_rr_output_info_is_active (output)) + { + gnome_rr_output_info_get_geometry (output, NULL, NULL, w, h); + } + else + { + *h = gnome_rr_output_info_get_preferred_height (output); + *w = gnome_rr_output_info_get_preferred_width (output); + } + + apply_rotation_to_geometry (output, w, h); +} + +#define SPACE 15 +#define MARGIN 15 + +static GList * +list_connected_outputs (CcDisplayPanel *self, int *total_w, int *total_h) +{ + int i, dummy; + GList *result = NULL; + GnomeRROutputInfo **outputs; + + if (!total_w) + total_w = &dummy; + if (!total_h) + total_h = &dummy; + + *total_w = 0; + *total_h = 0; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + int w, h; + + result = g_list_prepend (result, outputs[i]); + + get_geometry (outputs[i], &w, &h); + + *total_w += w; + *total_h += h; + } + } + + return g_list_reverse (result); +} + +static int +get_n_connected (CcDisplayPanel *self) +{ + GList *connected_outputs = list_connected_outputs (self, NULL, NULL); + int n = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + return n; +} + +static double +compute_scale (CcDisplayPanel *self) +{ + int available_w, available_h; + int total_w, total_h; + int n_monitors; + GdkRectangle viewport; + GList *connected_outputs; + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + + connected_outputs = list_connected_outputs (self, &total_w, &total_h); + + n_monitors = g_list_length (connected_outputs); + + g_list_free (connected_outputs); + + available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE; + available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE; + + return MIN ((double)available_w / total_w, (double)available_h / total_h); +} + +typedef struct Edge +{ + GnomeRROutputInfo *output; + int x1, y1; + int x2, y2; +} Edge; + +typedef struct Snap +{ + Edge *snapper; /* Edge that should be snapped */ + Edge *snappee; + int dy, dx; +} Snap; + +static void +add_edge (GnomeRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges) +{ + Edge e; + + e.x1 = x1; + e.x2 = x2; + e.y1 = y1; + e.y2 = y2; + e.output = output; + + g_array_append_val (edges, e); +} + +static void +list_edges_for_output (GnomeRROutputInfo *output, GArray *edges) +{ + int x, y, w, h; + + gnome_rr_output_info_get_geometry (output, &x, &y, &w, &h); + + apply_rotation_to_geometry (output, &w, &h); + + /* Top, Bottom, Left, Right */ + add_edge (output, x, y, x + w, y, edges); + add_edge (output, x, y + h, x + w, y + h, edges); + add_edge (output, x, y, x, y + h, edges); + add_edge (output, x + w, y, x + w, y + h, edges); +} + +static void +list_edges (GnomeRRConfig *config, GArray *edges) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + list_edges_for_output (outputs[i], edges); + } +} + +static gboolean +overlap (int s1, int e1, int s2, int e2) +{ + return (!(e1 < s2 || s1 >= e2)); +} + +static gboolean +horizontal_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2) + return FALSE; + + return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2); +} + +static gboolean +vertical_overlap (Edge *snapper, Edge *snappee) +{ + if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2) + return FALSE; + + return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2); +} + +static void +add_snap (GArray *snaps, Snap snap) +{ + if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200) + g_array_append_val (snaps, snap); +} + +static void +add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps) +{ + Snap snap; + + snap.snapper = snapper; + snap.snappee = snappee; + + if (horizontal_overlap (snapper, snappee)) + { + snap.dx = 0; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + } + else if (vertical_overlap (snapper, snappee)) + { + snap.dy = 0; + snap.dx = snappee->x1 - snapper->x1; + + add_snap (snaps, snap); + } + + /* Corner snaps */ + /* 1->1 */ + snap.dx = snappee->x1 - snapper->x1; + snap.dy = snappee->y1 - snapper->y1; + + add_snap (snaps, snap); + + /* 1->2 */ + snap.dx = snappee->x2 - snapper->x1; + snap.dy = snappee->y2 - snapper->y1; + + add_snap (snaps, snap); + + /* 2->2 */ + snap.dx = snappee->x2 - snapper->x2; + snap.dy = snappee->y2 - snapper->y2; + + add_snap (snaps, snap); + + /* 2->1 */ + snap.dx = snappee->x1 - snapper->x2; + snap.dy = snappee->y1 - snapper->y2; + + add_snap (snaps, snap); +} + +static void +list_snaps (GnomeRROutputInfo *output, GArray *edges, GArray *snaps) +{ + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + if (edge->output != output) + add_edge_snaps (output_edge, edge, snaps); + } + } + } +} + +#if 0 +static void +print_edge (Edge *edge) +{ + g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2); +} +#endif + +static gboolean +corner_on_edge (int x, int y, Edge *e) +{ + if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2) + return TRUE; + + if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2) + return TRUE; + + return FALSE; +} + +static gboolean +edges_align (Edge *e1, Edge *e2) +{ + if (corner_on_edge (e1->x1, e1->y1, e2)) + return TRUE; + + if (corner_on_edge (e2->x1, e2->y1, e1)) + return TRUE; + + return FALSE; +} + +static gboolean +output_is_aligned (GnomeRROutputInfo *output, GArray *edges) +{ + gboolean result = FALSE; + int i; + + for (i = 0; i < edges->len; ++i) + { + Edge *output_edge = &(g_array_index (edges, Edge, i)); + + if (output_edge->output == output) + { + int j; + + for (j = 0; j < edges->len; ++j) + { + Edge *edge = &(g_array_index (edges, Edge, j)); + + /* We are aligned if an output edge matches + * an edge of another output + */ + if (edge->output != output_edge->output) + { + if (edges_align (output_edge, edge)) + { + result = TRUE; + goto done; + } + } + } + } + } + done: + + return result; +} + +static void +get_output_rect (GnomeRROutputInfo *output, GdkRectangle *rect) +{ + gnome_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height); + + apply_rotation_to_geometry (output, &rect->width, &rect->height); +} + +static gboolean +output_overlaps (GnomeRROutputInfo *output, GnomeRRConfig *config) +{ + int i; + GdkRectangle output_rect; + GnomeRROutputInfo **outputs; + + g_assert (output != NULL); + + get_output_rect (output, &output_rect); + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (outputs[i] != output && gnome_rr_output_info_is_connected (outputs[i])) + { + GdkRectangle other_rect; + + get_output_rect (outputs[i], &other_rect); + if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL)) + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gnome_rr_config_is_aligned (GnomeRRConfig *config, GArray *edges) +{ + int i; + gboolean result = TRUE; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i]; ++i) + { + if (gnome_rr_output_info_is_connected (outputs[i])) + { + if (!output_is_aligned (outputs[i], edges)) + return FALSE; + + if (output_overlaps (outputs[i], config)) + return FALSE; + } + } + + return result; +} + +static gboolean +is_corner_snap (const Snap *s) +{ + return s->dx != 0 && s->dy != 0; +} + +static int +compare_snaps (gconstpointer v1, gconstpointer v2) +{ + const Snap *s1 = v1; + const Snap *s2 = v2; + int sv1 = MAX (ABS (s1->dx), ABS (s1->dy)); + int sv2 = MAX (ABS (s2->dx), ABS (s2->dy)); + int d; + + d = sv1 - sv2; + + /* This snapping algorithm is good enough for rock'n'roll, but + * this is probably a better: + * + * First do a horizontal/vertical snap, then + * with the new coordinates from that snap, + * do a corner snap. + * + * Right now, it's confusing that corner snapping + * depends on the distance in an axis that you can't actually see. + * + */ + if (d == 0) + { + if (is_corner_snap (s1) && !is_corner_snap (s2)) + return -1; + else if (is_corner_snap (s2) && !is_corner_snap (s1)) + return 1; + else + return 0; + } + else + { + return d; + } +} + +/* Sets a mouse cursor for a widget's window. As a hack, you can pass + * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's + * window's cursor to its default). + */ +static void +set_cursor (GtkWidget *widget, GdkCursorType type) +{ + GdkCursor *cursor; + GdkWindow *window; + + if (type == GDK_BLANK_CURSOR) + cursor = NULL; + else + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type); + + window = gtk_widget_get_window (widget); + + if (window) + gdk_window_set_cursor (window, cursor); + + if (cursor) + g_object_unref (cursor); +} + +static void +set_top_bar_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Drag to change primary display."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +on_top_bar_event (FooScrollArea *area, + FooScrollAreaEvent *event, + CcDisplayPanel *self) +{ + /* Ignore drops */ + if (event->type == FOO_DROP) + return; + + /* If the mouse is inside the top bar, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_HAND1); + + if (event->type == FOO_BUTTON_PRESS) + { + rebuild_gui (self); + set_top_bar_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + self->priv->dragging_top_bar = TRUE; + foo_scroll_area_begin_grab (area, (FooScrollAreaEventFunc) on_top_bar_event, self); + } + + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + self->priv->dragging_top_bar = FALSE; + set_top_bar_tooltip (self, FALSE); + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +set_monitors_tooltip (CcDisplayPanel *self, gboolean is_dragging) +{ + const char *text; + + if (is_dragging) + text = NULL; + else + text = _("Select a monitor to change its properties; drag it to rearrange its placement."); + + gtk_widget_set_tooltip_text (self->priv->area, text); +} + +static void +set_primary_output (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + int i; + GnomeRROutputInfo **outputs; + + outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + for (i = 0; outputs[i] != NULL; ++i) + gnome_rr_output_info_set_primary (outputs[i], outputs[i] == output); + + gtk_widget_queue_draw (WID ("self->priv->area")); + /* refresh the combobox */ + refresh_unity_launcher_placement (self); +} + +static void +on_output_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + GnomeRROutputInfo *output = data; + CcDisplayPanel *self = g_object_get_data (G_OBJECT (area), "panel"); + + if (event->type == FOO_DRAG_HOVER) + { + if (gnome_rr_output_info_is_active (output) && self->priv->dragging_top_bar) + set_primary_output (self, output); + return; + } + if (event->type == FOO_DROP) + { + /* Activate new primary? */ + return; + } + + /* If the mouse is inside the outputs, set the cursor to "you can move me". See + * on_canvas_event() for where we reset the cursor to the default if it + * exits the outputs' area. + */ + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + set_cursor (GTK_WIDGET (area), GDK_FLEUR); + + if (event->type == FOO_BUTTON_PRESS) + { + GrabInfo *info; + + self->priv->current_output = output; + + rebuild_gui (self); + set_monitors_tooltip (self, TRUE); + + if (!gnome_rr_config_get_clone (self->priv->current_configuration) && get_n_connected (self) > 1) + { + int output_x, output_y; + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + + foo_scroll_area_begin_grab (area, on_output_event, data); + + info = g_new0 (GrabInfo, 1); + info->grab_x = event->x; + info->grab_y = event->y; + info->output_x = output_x; + info->output_y = output_y; + + g_object_set_data (G_OBJECT (output), "grab-info", info); + } + foo_scroll_area_invalidate (area); + } + else + { + if (foo_scroll_area_is_grabbed (area)) + { + GrabInfo *info = g_object_get_data (G_OBJECT (output), "grab-info"); + double scale = compute_scale (self); + int old_x, old_y; + int width, height; + int new_x, new_y; + int i; + GArray *edges, *snaps, *new_edges; + + gnome_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height); + new_x = info->output_x + (event->x - info->grab_x) / scale; + new_y = info->output_y + (event->y - info->grab_y) / scale; + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + snaps = g_array_new (TRUE, TRUE, sizeof (Snap)); + new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + list_edges (self->priv->current_configuration, edges); + list_snaps (output, edges, snaps); + + g_array_sort (snaps, compare_snaps); + + gnome_rr_output_info_set_geometry (output, new_x, new_y, width, height); + + for (i = 0; i < snaps->len; ++i) + { + Snap *snap = &(g_array_index (snaps, Snap, i)); + GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge)); + + gnome_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height); + + g_array_set_size (new_edges, 0); + list_edges (self->priv->current_configuration, new_edges); + + if (gnome_rr_config_is_aligned (self->priv->current_configuration, new_edges)) + { + g_array_free (new_edges, TRUE); + break; + } + else + { + gnome_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height); + } + } + + g_array_free (new_edges, TRUE); + g_array_free (snaps, TRUE); + g_array_free (edges, TRUE); + + if (event->type == FOO_BUTTON_RELEASE) + { + foo_scroll_area_end_grab (area, event); + set_monitors_tooltip (self, FALSE); + + g_free (g_object_get_data (G_OBJECT (output), "grab-info")); + g_object_set_data (G_OBJECT (output), "grab-info", NULL); + +#if 0 + g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height); +#endif + } + + foo_scroll_area_invalidate (area); + } + } +} + +static void +on_canvas_event (FooScrollArea *area, + FooScrollAreaEvent *event, + gpointer data) +{ + /* If the mouse exits the outputs, reset the cursor to the default. See + * on_output_event() for where we set the cursor to the movement cursor if + * it is over one of the outputs. + */ + set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR); +} + +static PangoLayout * +get_display_name (CcDisplayPanel *self, + GnomeRROutputInfo *output) +{ + PangoLayout *layout; + char *text; + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + text = mirror_monitor_name (); + else + text = g_strdup (gnome_rr_output_info_get_display_name (output)); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + return layout; +} + +static void +paint_background (FooScrollArea *area, + cairo_t *cr) +{ + GdkRectangle viewport; + GtkWidget *widget; + GtkStyleContext *context; + GdkRGBA fg, bg; + + widget = GTK_WIDGET (area); + + foo_scroll_area_get_viewport (area, &viewport); + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg); + + cairo_set_source_rgba (cr, + (fg.red + bg.red) / 2, + (fg.green + bg.green) / 2, + (fg.blue + bg.blue) / 2, + (fg.alpha + bg.alpha) / 2); + + cairo_rectangle (cr, + viewport.x, viewport.y, + viewport.width, viewport.height); + + cairo_fill_preserve (cr); + + foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL); + + cairo_set_source_rgba (cr, + 0.7 * bg.red, + 0.7 * bg.green, + 0.7 * bg.blue, + 0.7 * bg.alpha); + + cairo_stroke (cr); +} + +static void +color_shade (double *r, + double *g, + double *b, + double k) +{ + double h, s, v; + + gtk_rgb_to_hsv (*r, *g, *b, &h, &s, &v); + + s *= k; + if (s > 1.0) + s = 1.0; + else if (s < 0.0) + s = 0.0; + + v *= k; + if (v > 1.0) + v = 1.0; + else if (v < 0.0) + v = 0.0; + + gtk_hsv_to_rgb (h, s, v, r, g, b); +} + +static void +paint_output (CcDisplayPanel *self, cairo_t *cr, int i) +{ + int w, h; + double scale = compute_scale (self); + double x, y; + int output_x, output_y; + GnomeRRRotation rotation; + int total_w, total_h; + GList *connected_outputs = list_connected_outputs (self, &total_w, &total_h); + GnomeRROutputInfo *output = g_list_nth (connected_outputs, i)->data; + PangoLayout *layout = get_display_name (self, output); + PangoRectangle ink_extent, log_extent; + GdkRectangle viewport; + GdkRGBA output_color; + double r, g, b; + double available_w; + double factor; + + cairo_save (cr); + + foo_scroll_area_get_viewport (FOO_SCROLL_AREA (self->priv->area), &viewport); + get_geometry (output, &w, &h); + +#if 0 + g_debug ("%s (%p) geometry %d %d %d primary=%d", output->name, output->name, + w, h, output->rate, output->primary); +#endif + + viewport.height -= 2 * MARGIN; + viewport.width -= 2 * MARGIN; + + gnome_rr_output_info_get_geometry (output, &output_x, &output_y, NULL, NULL); + x = output_x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0; + y = output_y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0; + +#if 0 + g_debug ("scaled: %f %f", x, y); + + g_debug ("scale: %f", scale); + + g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5); +#endif + + cairo_translate (cr, + x + (w * scale + 0.5) / 2, + y + (h * scale + 0.5) / 2); + + /* rotation is already applied in get_geometry */ + + rotation = gnome_rr_output_info_get_rotation (output); + if (rotation & GNOME_RR_REFLECT_X) + cairo_scale (cr, -1, 1); + + if (rotation & GNOME_RR_REFLECT_Y) + cairo_scale (cr, 1, -1); + + cairo_translate (cr, + - x - (w * scale + 0.5) / 2, + - y - (h * scale + 0.5) / 2); + + if (output == self->priv->current_output) + { + GtkStyleContext *context; + GdkRGBA color; + + context = gtk_widget_get_style_context (self->priv->area); + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); + + cairo_rectangle (cr, x - 2, y - 2, w * scale + 0.5 + 4, h * scale + 0.5 + 4); + + cairo_set_line_width (cr, 4); + cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5); + cairo_stroke (cr); + } + + cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5); + cairo_clip_preserve (cr); + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &output_color); + r = output_color.red; + g = output_color.green; + b = output_color.blue; + + if (!gnome_rr_output_info_is_active (output)) + { + /* If the output is turned off, just darken the selected color */ + color_shade (&r, &g, &b, 0.4); + } + + cairo_set_source_rgba (cr, r, g, b, 1.0); + + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, on_output_event, output); + cairo_fill (cr); + + cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + + cairo_stroke (cr); + cairo_set_line_width (cr, 2); + + cairo_save (cr); + + layout_set_font (layout, "Sans 10"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */ + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + ((h * scale + 0.5) - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + if (gnome_rr_output_info_is_active (output)) + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + else + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + cairo_restore (cr); + + /* Only display a launcher on all or primary monitor */ + if (is_unity_session ()) + { + if (gnome_rr_output_info_is_active (output) && (unity_launcher_on_all_monitors (self->priv->unity_settings) || gnome_rr_output_info_get_primary (output))) + { + cairo_rectangle (cr, x, y, 10, h * scale + 0.5); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + cairo_rectangle (cr, x + 1, y + 6, 8, 8); + cairo_rectangle (cr, x + 1, y + 16, 8, 8); + cairo_rectangle (cr, x + 1, y + 26, 8, 8); + cairo_rectangle (cr, x + 1, y + 36, 8, 8); + cairo_rectangle (cr, x + 1, y + h * scale + 0.5 - 10, 8, 8); + cairo_fill (cr); + } + } + + if (gnome_rr_output_info_get_primary (output) && !is_unity_session ()) + { + const char *clock_format; + char *text; + gboolean use_24; + GDateTime *dt; + GDesktopClockFormat value; + + /* top bar */ + cairo_rectangle (cr, x, y, w * scale + 0.5, TOP_BAR_HEIGHT); + cairo_set_source_rgb (cr, 0, 0, 0); + foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (self->priv->area), + cr, + (FooScrollAreaEventFunc) on_top_bar_event, + self); + + cairo_fill (cr); + + /* clock */ + value = g_settings_get_enum (self->priv->clock_settings, CLOCK_FORMAT_KEY); + use_24 = value == G_DESKTOP_CLOCK_FORMAT_24H; + if (use_24) + clock_format = _("%a %R"); + else + clock_format = _("%a %l:%M %p"); + + dt = g_date_time_new_now_local (); + text = g_date_time_format (dt, clock_format); + g_date_time_unref (dt); + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self->priv->area), text); + g_free (text); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + + layout_set_font (layout, "Sans 4"); + pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent); + + if (available_w < ink_extent.width) + factor = available_w / ink_extent.width; + else + factor = 1.0; + + cairo_move_to (cr, + x + ((w * scale + 0.5) - factor * log_extent.width) / 2, + y + (TOP_BAR_HEIGHT - factor * log_extent.height) / 2); + + cairo_scale (cr, factor, factor); + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + } + + cairo_restore (cr); +} + +static void +on_area_paint (FooScrollArea *area, + cairo_t *cr, + gpointer data) +{ + CcDisplayPanel *self = data; + GList *connected_outputs = NULL; + GList *list; + + paint_background (area, cr); + + if (!self->priv->current_configuration) + return; + + connected_outputs = list_connected_outputs (self, NULL, NULL); + + for (list = connected_outputs; list != NULL; list = list->next) + { + paint_output (self, cr, g_list_position (connected_outputs, list)); + + if (gnome_rr_config_get_clone (self->priv->current_configuration)) + break; + } +} + +static void +make_text_combo (GtkWidget *widget, int sort_column) +{ + GtkComboBox *box = GTK_COMBO_BOX (widget); + GtkListStore *store = gtk_list_store_new ( + NUM_COLS, + G_TYPE_STRING, /* Text */ + G_TYPE_INT, /* Width */ + G_TYPE_INT, /* Height */ + G_TYPE_INT, /* Frequency */ + G_TYPE_INT, /* Width * Height */ + G_TYPE_INT); /* Rotation */ + + GtkCellRenderer *cell; + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget)); + + gtk_combo_box_set_model (box, GTK_TREE_MODEL (store)); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell, + "text", 0, + NULL); + + if (sort_column != -1) + { + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + sort_column, + GTK_SORT_DESCENDING); + } +} + +static void +compute_virtual_size_for_configuration (GnomeRRConfig *config, int *ret_width, int *ret_height) +{ + int i; + int width, height; + int output_x, output_y, output_width, output_height; + GnomeRROutputInfo **outputs; + + width = height = 0; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) + { + if (gnome_rr_output_info_is_active (outputs[i])) + { + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + width = MAX (width, output_x + output_width); + height = MAX (height, output_y + output_height); + } + } + + *ret_width = width; + *ret_height = height; +} + +static void +check_required_virtual_size (CcDisplayPanel *self) +{ + int req_width, req_height; + int min_width, max_width; + int min_height, max_height; + + compute_virtual_size_for_configuration (self->priv->current_configuration, &req_width, &req_height); + + gnome_rr_screen_get_ranges (self->priv->screen, &min_width, &max_width, &min_height, &max_height); + +#if 0 + g_debug ("X Server supports:"); + g_debug ("min_width = %d, max_width = %d", min_width, max_width); + g_debug ("min_height = %d, max_height = %d", min_height, max_height); + + g_debug ("Requesting size of %dx%d", req_width, req_height); +#endif + + if (!(min_width <= req_width && req_width <= max_width + && min_height <= req_height && req_height <= max_height)) + { + /* FIXME: present a useful dialog, maybe even before the user tries to Apply */ +#if 0 + g_debug ("Your X server needs a larger Virtual size!"); +#endif + } +} + +static void +begin_version2_apply_configuration (CcDisplayPanel *self, GdkWindow *parent_window, guint32 timestamp) +{ + XID parent_window_xid; + GError *error = NULL; + + parent_window_xid = GDK_WINDOW_XID (parent_window); + + self->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/XRANDR", + "org.gnome.SettingsDaemon.XRANDR_2", + NULL, + &error); + if (self->priv->proxy == NULL) { + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_error_free (error); + return; + } + + g_dbus_proxy_call (self->priv->proxy, + "ApplyConfiguration", + g_variant_new ("(xx)", (gint64) parent_window_xid, (gint64) timestamp), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + apply_configuration_returned_cb, + self); +} + +static void +ensure_current_configuration_is_saved (void) +{ + GnomeRRScreen *rr_screen; + GnomeRRConfig *rr_config; + + /* Normally, gnome_rr_config_save() creates a backup file based on the + * old monitors.xml. However, if *that* file didn't exist, there is + * nothing from which to create a backup. So, here we'll save the + * current/unchanged configuration and then let our caller call + * gnome_rr_config_save() again with the new/changed configuration, so + * that there *will* be a backup file in the end. + */ + + rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL); /* NULL-GError */ + if (!rr_screen) + return; + + rr_config = gnome_rr_config_new_current (rr_screen, NULL); + gnome_rr_config_ensure_primary (rr_config); + gnome_rr_config_save (rr_config, NULL); /* NULL-GError */ + + g_object_unref (rr_config); + g_object_unref (rr_screen); +} + +static void +apply_configuration_returned_cb (GObject *proxy, + GAsyncResult *res, + gpointer data) +{ + CcDisplayPanel *self = data; + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if (error) + error_message (self, _("Failed to apply configuration: %s"), error->message); + g_clear_error (&error); + if (result) + g_variant_unref (result); + + g_object_unref (self->priv->proxy); + self->priv->proxy = NULL; + + gtk_widget_set_sensitive (self->priv->panel, TRUE); +} + +static gboolean +sanitize_and_save_configuration (CcDisplayPanel *self) +{ + GError *error; + + gnome_rr_config_sanitize (self->priv->current_configuration); + gnome_rr_config_ensure_primary (self->priv->current_configuration); + + check_required_virtual_size (self); + + foo_scroll_area_invalidate (FOO_SCROLL_AREA (self->priv->area)); + + ensure_current_configuration_is_saved (); + + error = NULL; + if (!gnome_rr_config_save (self->priv->current_configuration, &error)) + { + error_message (self, _("Could not save the monitor configuration"), error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +static void +apply (CcDisplayPanel *self) +{ + GdkWindow *window; + + self->priv->apply_button_clicked_timestamp = gtk_get_current_event_time (); + + if (!sanitize_and_save_configuration (self)) + return; + + g_assert (self->priv->proxy == NULL); + + gtk_widget_set_sensitive (self->priv->panel, FALSE); + + window = gtk_widget_get_window (gtk_widget_get_toplevel (self->priv->panel)); + + begin_version2_apply_configuration (self, window, + self->priv->apply_button_clicked_timestamp); +} + +#if 0 +/* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */ +static gboolean +driver_is_randr_10 (GnomeRRConfig *config) +{ + /* In the Xorg code, see xserver/randr/rrinfo.c:RRScanOldConfig(). It gets + * called when the graphics driver doesn't support RANDR 1.2 yet, just 1.0. + * In that case, the X server's base code (which supports RANDR 1.2) will + * simulate having a single output called "default". For drivers that *do* + * support RANDR 1.2, the separate outputs will be named differently, we + * hope. + * + * This heuristic is courtesy of Dirk Mueller + * + * FIXME: however, we don't even check for XRRQueryVersion() returning 1.2, neither + * here nor in gnome-desktop/libgnomedesktop*.c. Do we need to check for that, + * or is gnome_rr_screen_new()'s return value sufficient? + */ + + return (count_all_outputs (config) == 1 && strcmp (gnome_rr_output_info_get_name (gnome_rr_config_get_outputs (config)[0]), "default") == 0); +} +#endif + +static void +on_detect_displays (GtkWidget *widget, gpointer data) +{ + CcDisplayPanel *self = data; + GError *error; + + error = NULL; + if (!gnome_rr_screen_refresh (self->priv->screen, &error)) { + if (error) { + error_message (self, _("Could not detect displays"), error->message); + g_error_free (error); + } + } +} + +static GnomeRROutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) +{ + int i; + int nearest_index; + int nearest_dist; + GnomeRROutputInfo **outputs; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + int dist_x, dist_y; + int output_x, output_y, output_width, output_height; + + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (x < output_x) + dist_x = output_x - x; + else if (x >= output_x + output_width) + dist_x = x - (output_x + output_width) + 1; + else + dist_x = 0; + + if (y < output_y) + dist_y = output_y - y; + else if (y >= output_y + output_height) + dist_y = y - (output_y + output_height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return outputs[nearest_index]; + else + return NULL; +} + +/* Gets the output that contains the largest intersection with the window. + * Logic stolen from gdk_screen_get_monitor_at_window(). + */ +static GnomeRROutputInfo * +get_output_for_window (GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + GnomeRROutputInfo **outputs; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + GdkRectangle output_rect, intersection; + + gnome_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); + + if (gnome_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +static void +dialog_toplevel_focus_changed (GtkWindow *window, + GParamSpec *pspec, + CcDisplayPanel *self) +{ + if (self->priv->labeler == NULL) + return; + if (gtk_window_has_toplevel_focus (window)) + gnome_rr_labeler_show (self->priv->labeler); + else + gnome_rr_labeler_hide (self->priv->labeler); +} + +static void +on_toplevel_realized (GtkWidget *widget, + CcDisplayPanel *self) +{ + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (widget)); + rebuild_gui (self); +} + +/* We select the current output, i.e. select the one being edited, based on + * which output is showing the configuration dialog. + */ +static void +select_current_output_from_dialog_position (CcDisplayPanel *self) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (self->priv->panel); + + if (gtk_widget_get_realized (toplevel)) { + self->priv->current_output = get_output_for_window (self->priv->current_configuration, + gtk_widget_get_window (toplevel)); + rebuild_gui (self); + } else { + g_signal_connect (toplevel, "realize", G_CALLBACK (on_toplevel_realized), self); + self->priv->current_output = NULL; + } +} + +/* This is a GtkWidget::map-event handler. We wait for the display-properties + * dialog to be mapped, and then we select the output which corresponds to the + * monitor on which the dialog is being shown. + */ +static gboolean +dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + CcDisplayPanel *self = data; + + select_current_output_from_dialog_position (self); + return FALSE; +} + +static void +stickyedge_widget_refresh (GtkSwitch *switcher, GSettings *settings) +{ + gboolean stickyedge_enabled = g_settings_get_boolean (settings, UNITY_STICKY_EDGE_KEY); + + gtk_switch_set_active (switcher, stickyedge_enabled); +} + +static void +ext_stickyedge_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + stickyedge_widget_refresh (GTK_SWITCH (user_data), settings); +} + +static void +on_stickyedge_changed (GtkSwitch *switcher, GParamSpec *pspec, gpointer user_data) +{ + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gboolean enabled = gtk_switch_get_active (GTK_SWITCH (switcher)); + + /* 3d */ + g_settings_set_boolean (self->priv->unity_settings, UNITY_STICKY_EDGE_KEY, enabled); + /* 2d */ + if (self->priv->unity2d_settings_main) + g_settings_set_boolean (self->priv->unity2d_settings_main, "sticky-edges", enabled); +} + +static gboolean +unity_launcher_on_all_monitors (GSettings *settings) +{ + gint value = g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY); + return (value == 0); +} + +static GdkPixbuf* +get_monitor_pixbuf (CcDisplayPanel *self, GnomeRROutputInfo *output) +{ + GdkRGBA color; + cairo_surface_t *cairo_surface; + cairo_t *cr; + int monitor_width = 30; + int monitor_height = 15; + + gnome_rr_labeler_get_rgba_for_output (self->priv->labeler, output, &color); + + cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, monitor_width, monitor_height); + cr = cairo_create (cairo_surface); + cairo_surface_destroy (cairo_surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, color.red, color.green, color.blue); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 0, 0, 0, 1.0); + cairo_rectangle (cr, 0.5, 0.5, monitor_width - 1, monitor_height - 1); + cairo_stroke (cr); + + return gdk_pixbuf_get_from_surface (cairo_get_target (cr), 0, 0, monitor_width, monitor_height); +} + +static void +refresh_unity_launcher_placement (CcDisplayPanel *self) +{ + GtkWidget *launcher_placement_combo = WID ("launcher_placement_combo"); + GtkListStore *liststore; + GtkTreeIter iter; + GList *connected_outputs = NULL; + GList *list; + gboolean launcher_on_all_monitors = unity_launcher_on_all_monitors (self->priv->unity_settings); + gint index_of_primary_screen = 0; + gint i; + + liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "available_launcher_placement_store"); + gtk_list_store_clear (liststore); + + connected_outputs = list_connected_outputs (self, NULL, NULL); + for (list = connected_outputs, i = 0; list != NULL; list = list->next) + { + char *monitor_name; + GdkPixbuf *monitor_pixbuf; + GnomeRROutputInfo *output = list->data; + + if (!gnome_rr_output_info_is_active (output)) + continue; + + gtk_list_store_append (liststore, &iter); + monitor_name = g_strdup (gnome_rr_output_info_get_display_name (output)); + monitor_pixbuf = get_monitor_pixbuf (self, output); + + gtk_list_store_set (liststore, &iter, 0, monitor_pixbuf, 1, monitor_name, -1); + + /* select it if primary and only one launcher */ + if (gnome_rr_output_info_get_primary (output) && (!launcher_on_all_monitors)) + index_of_primary_screen = i; + i++; + + g_object_unref (monitor_pixbuf); + g_free (monitor_name); + } + + // FIXME: check autosort? + gtk_list_store_append (liststore, &iter); + gtk_list_store_set (liststore, &iter, 0, NULL, 1, _("All displays"), -1); + + if (launcher_on_all_monitors) + index_of_primary_screen = i; + + gtk_combo_box_set_active (GTK_COMBO_BOX (launcher_placement_combo), index_of_primary_screen); +} + +static gboolean +switcher_set_to_launcher_on_all_monitors (CcDisplayPanel *self) +{ + GtkComboBox *combo = GTK_COMBO_BOX (WID ("launcher_placement_combo")); + gint active = gtk_combo_box_get_active (combo); + gint number_items = gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), + NULL); + return (active == number_items - 1); +} + +static void +ext_launcher_placement_changed_callback (GSettings* settings, + guint key, + gpointer user_data) +{ + // add some crazyness as 2d/3d are not using the same keys + CcDisplayPanel *self = CC_DISPLAY_PANEL (user_data); + gint launcher_unity_value = 0; + + // two options support: all monitors (0)i or just primary desktop (hence set to 1, not any other number) + if (! switcher_set_to_launcher_on_all_monitors (self)) + launcher_unity_value = 1; + + if (g_settings_get_int (settings, UNITY_LAUNCHER_ALL_MONITORS_KEY) != launcher_unity_value) + refresh_unity_launcher_placement (self); +} + +static void +on_launcher_placement_combo_changed (GtkComboBox *combo, CcDisplayPanel *self) +{ + gint active = gtk_combo_box_get_active (combo); + gint i; + gint index_on_combo = 0; + + if (active < 0) + return; + gint value = 0; + gboolean on_all_monitors = switcher_set_to_launcher_on_all_monitors (self); + + if (!on_all_monitors) { + value = 1; + // set the primary output if needed + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (self->priv->current_configuration); + + for (i = 0; outputs[i] != NULL; ++i) + { + GnomeRROutputInfo *output = outputs[i]; + if (!gnome_rr_output_info_is_active (output)) + continue; + + if ((active == index_on_combo) && !gnome_rr_output_info_get_primary (output)) + { + set_primary_output (self, output); + break; + } + index_on_combo++; + } + } + + /* 3d */ + if (self->priv->unity_settings) + g_settings_set_int (self->priv->unity_settings, UNITY_LAUNCHER_ALL_MONITORS_KEY, value); + /* 2d */ + if (self->priv->unity2d_settings_launcher) + g_settings_set_boolean (self->priv->unity2d_settings_launcher, "only-one-launcher", !on_all_monitors); +} + +static void +setup_unity_settings (CcDisplayPanel *self) +{ + const gchar * const *schemas; + + /* Only use the unity-2d schema if it's installed */ + schemas = g_settings_list_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY2D_GSETTINGS_LAUNCHER) == 0) + { + self->priv->unity2d_settings_main = g_settings_new (UNITY2D_GSETTINGS_MAIN); + self->priv->unity2d_settings_launcher = g_settings_new (UNITY2D_GSETTINGS_LAUNCHER); + break; + } + schemas++; + } + schemas = g_settings_list_relocatable_schemas (); + while (*schemas != NULL) + { + if (g_strcmp0 (*schemas, UNITY_GSETTINGS_SCHEMA) == 0) + { + self->priv->unity_settings = g_settings_new_with_path (UNITY_GSETTINGS_SCHEMA, UNITY_GSETTINGS_PATH); + break; + } + schemas++; + } + + if (!self->priv->unity_settings) + return; + + GtkWidget *sticky_edge_switch = WID ("stickyedge_switch"); + g_signal_connect (sticky_edge_switch, "notify::active", + G_CALLBACK (on_stickyedge_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_STICKY_EDGE_KEY, + G_CALLBACK (ext_stickyedge_changed_callback), sticky_edge_switch); + stickyedge_widget_refresh (GTK_SWITCH (sticky_edge_switch), self->priv->unity_settings); + + g_signal_connect (G_OBJECT (WID ("launcher_placement_combo")), "changed", + G_CALLBACK (on_launcher_placement_combo_changed), self); + g_signal_connect (self->priv->unity_settings, "changed::" UNITY_LAUNCHER_ALL_MONITORS_KEY, + G_CALLBACK (ext_launcher_placement_changed_callback), self); +} + +static void +cc_display_panel_init (CcDisplayPanel *self) +{ +} + +static GObject * +cc_display_panel_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) +{ + GtkBuilder *builder; + GtkWidget *align; + GError *error; + GObject *obj; + CcDisplayPanel *self; + CcShell *shell; + GtkWidget *toplevel; + gchar *objects[] = {"display-panel", "available_launcher_placement_store", NULL}; + + obj = G_OBJECT_CLASS (cc_display_panel_parent_class)->constructor (gtype, n_properties, properties); + self = CC_DISPLAY_PANEL (obj); + self->priv = DISPLAY_PANEL_PRIVATE (self); + + error = NULL; + self->priv->builder = builder = gtk_builder_new (); + + if (!gtk_builder_add_objects_from_file (builder, UIDIR "/display-capplet.ui", objects, &error)) + { + g_warning ("Could not parse UI definition: %s", error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); + g_signal_connect (self->priv->screen, "changed", G_CALLBACK (on_screen_changed), self); + if (!self->priv->screen) + { + error_message (NULL, _("Could not get screen information"), error->message); + g_error_free (error); + g_object_unref (builder); + return obj; + } + + self->priv->clock_settings = g_settings_new (CLOCK_SCHEMA); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + self->priv->focus_id = g_signal_connect (toplevel, "notify::has-toplevel-focus", + G_CALLBACK (dialog_toplevel_focus_changed), self); + + self->priv->panel = WID ("display-panel"); + g_signal_connect_after (self->priv->panel, "show", + G_CALLBACK (dialog_map_event_cb), self); + + self->priv->current_monitor_event_box = WID ("current_monitor_event_box"); + self->priv->current_monitor_label = WID ("current_monitor_label"); + + self->priv->monitor_switch = WID ("monitor_switch"); + g_signal_connect (self->priv->monitor_switch, "notify::active", + G_CALLBACK (monitor_switch_active_cb), self); + + self->priv->resolution_combo = WID ("resolution_combo"); + g_signal_connect (self->priv->resolution_combo, "changed", + G_CALLBACK (on_resolution_changed), self); + + self->priv->rotation_combo = WID ("rotation_combo"); + g_signal_connect (self->priv->rotation_combo, "changed", + G_CALLBACK (on_rotation_changed), self); + + self->priv->clone_checkbox = WID ("clone_checkbox"); + g_signal_connect (self->priv->clone_checkbox, "toggled", + G_CALLBACK (on_clone_changed), self); + + self->priv->clone_label = WID ("clone_resolution_warning_label"); + + g_signal_connect (WID ("detect_displays_button"), + "clicked", G_CALLBACK (on_detect_displays), self); + + make_text_combo (self->priv->resolution_combo, 4); + make_text_combo (self->priv->rotation_combo, -1); + + /* Scroll Area */ + self->priv->area = (GtkWidget *)foo_scroll_area_new (); + + g_object_set_data (G_OBJECT (self->priv->area), "panel", self); + + set_monitors_tooltip (self, FALSE); + + /* FIXME: this should be computed dynamically */ + foo_scroll_area_set_min_size (FOO_SCROLL_AREA (self->priv->area), 0, 200); + gtk_widget_show (self->priv->area); + g_signal_connect (self->priv->area, "paint", + G_CALLBACK (on_area_paint), self); + g_signal_connect (self->priv->area, "viewport_changed", + G_CALLBACK (on_viewport_changed), self); + + align = WID ("align"); + + gtk_container_add (GTK_CONTAINER (align), self->priv->area); + + on_screen_changed (self->priv->screen, self); + + g_signal_connect_swapped (WID ("apply_button"), + "clicked", G_CALLBACK (apply), self); + + /* Unity settings */ + if (is_unity_session ()) + setup_unity_settings (self); + else + { + gtk_widget_hide (WID ("unity_launcher_placement_sep")); + gtk_widget_hide (WID ("launcher_placement_label")); + gtk_widget_hide (WID ("sticky_edge_label")); + gtk_widget_hide (WID ("launcher_placement_combo")); + gtk_widget_hide (WID ("stickyedge_switch")); + } + + gtk_widget_show (self->priv->panel); + gtk_container_add (GTK_CONTAINER (self), self->priv->panel); + + return obj; +} + +void +cc_display_panel_register (GIOModule *module) +{ + cc_display_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_DISPLAY_PANEL, + "display", 0); +} diff -Nru gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/Makefile.am gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/Makefile.am --- gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_move_rr_labeler.patch/panels/display/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,75 @@ +# This is used in PANEL_CFLAGS +cappletname = display + +uidir = $(pkgdatadir)/ui +dist_ui_DATA = display-capplet.ui + +MARSHALFILES = foo-marshal.c foo-marshal.h +BUILT_SOURCES = $(MARSHALFILES) + +foo-marshal.c: foo-marshal.h + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=foo_marshal $(srcdir)/foo-marshal.list --header --body > foo-marshal.c ) +foo-marshal.h: foo-marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=foo_marshal $(srcdir)/foo-marshal.list --header > foo-marshal.h ) + +ccpanelsdir = $(PANELS_DIR) +ccpanels_LTLIBRARIES = libdisplay.la + +libdisplay_la_SOURCES = \ + display-module.c \ + cc-display-panel.c \ + cc-display-panel.h \ + scrollarea.c \ + scrollarea.h \ + $(MARSHALFILES) + +libdisplay_la_LIBADD = $(PANEL_LIBS) $(DISPLAY_PANEL_LIBS) +libdisplay_la_LDFLAGS = $(PANEL_LDFLAGS) + +# You will need a recent intltool or the patch from this bug +# http://bugzilla.gnome.org/show_bug.cgi?id=462312 +@INTLTOOL_POLICY_RULE@ + +@INTLTOOL_DESKTOP_RULE@ + +icons16dir = $(datadir)/icons/hicolor/16x16/apps +dist_icons16_DATA = icons/16x16/preferences-desktop-display.png +icons22dir = $(datadir)/icons/hicolor/22x22/apps +dist_icons22_DATA = icons/22x22/preferences-desktop-display.png +icons24dir = $(datadir)/icons/hicolor/24x24/apps +dist_icons24_DATA = icons/24x24/preferences-desktop-display.png +icons32dir = $(datadir)/icons/hicolor/32x32/apps +dist_icons32_DATA = icons/32x32/preferences-desktop-display.png +iconssvgdir = $(datadir)/icons/hicolor/scalable/apps +dist_iconssvg_DATA = icons/scalable/preferences-desktop-display.svg + +desktopdir = $(datadir)/applications +Desktop_in_files = gnome-display-panel.desktop.in +desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop) + +INCLUDES = $(PANEL_CFLAGS) \ + $(DISPLAY_PANEL_CFLAGS) \ + -DSBINDIR="\"$(sbindir)\"" \ + -DUIDIR="\"$(uidir)\"" \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + -DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" + +CLEANFILES = $(Desktop_in_files) $(desktop_DATA) + +if MAINTAINER_MODE +gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor +install-data-hook: update-icon-cache +uninstall-hook: update-icon-cache +update-icon-cache: + @-if test -z "$(DESTDIR)"; then \ + echo "Updating Gtk icon cache."; \ + $(gtk_update_icon_cache); \ + else \ + echo "*** Icon cache not updated. After (un)install, run this:"; \ + echo "*** $(gtk_update_icon_cache)"; \ + fi +endif + +EXTRA_DIST = foo-marshal.list + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-model.c gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-model.c --- gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-model.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-model.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,437 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2011 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE +#include + +#include "cc-online-accounts-model.h" + +struct _GoaPanelAccountsModel +{ + GtkListStore parent_instance; + + GoaClient *client; +}; + +typedef struct +{ + GtkListStoreClass parent_class; +} GoaPanelAccountsModelClass; + +enum +{ + PROP_0, + PROP_CLIENT, +}; + +static void init_model (GoaPanelAccountsModel *model); + +static gboolean +find_iter_for_object (GoaPanelAccountsModel *model, + GoaObject *object, + GtkTreeIter *out_iter); + +static void on_account_added (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static void on_account_removed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static void on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +G_DEFINE_TYPE (GoaPanelAccountsModel, goa_panel_accounts_model, GTK_TYPE_LIST_STORE); + +static void +goa_panel_accounts_model_finalize (GObject *object) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (object); + + g_signal_handlers_disconnect_by_func (model->client, G_CALLBACK (on_account_added), model); + g_signal_handlers_disconnect_by_func (model->client, G_CALLBACK (on_account_removed), model); + g_signal_handlers_disconnect_by_func (model->client, G_CALLBACK (on_account_changed), model); + g_object_unref (model->client); + + G_OBJECT_CLASS (goa_panel_accounts_model_parent_class)->finalize (object); +} + +static void +goa_panel_accounts_model_init (GoaPanelAccountsModel *model) +{ +} + +static void +goa_panel_accounts_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (object); + + switch (prop_id) + { + case PROP_CLIENT: + g_value_set_object (value, goa_panel_accounts_model_get_client (model)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +goa_panel_accounts_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (object); + + switch (prop_id) + { + case PROP_CLIENT: + model->client = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +goa_panel_accounts_model_constructed (GObject *object) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (object); + GType types[GOA_PANEL_ACCOUNTS_MODEL_N_COLUMNS]; + + G_STATIC_ASSERT (5 == GOA_PANEL_ACCOUNTS_MODEL_N_COLUMNS); + + types[0] = G_TYPE_STRING; + types[1] = GOA_TYPE_OBJECT; + types[2] = G_TYPE_BOOLEAN; + types[3] = G_TYPE_STRING; + types[4] = G_TYPE_ICON; + + gtk_list_store_set_column_types (GTK_LIST_STORE (model), + GOA_PANEL_ACCOUNTS_MODEL_N_COLUMNS, + types); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_SORT_KEY, + GTK_SORT_ASCENDING); + + g_signal_connect (model->client, + "account-added", + G_CALLBACK (on_account_added), + model); + g_signal_connect (model->client, + "account-removed", + G_CALLBACK (on_account_removed), + model); + g_signal_connect (model->client, + "account-changed", + G_CALLBACK (on_account_changed), + model); + + init_model (model); + + if (G_OBJECT_CLASS (goa_panel_accounts_model_parent_class)->constructed != NULL) + G_OBJECT_CLASS (goa_panel_accounts_model_parent_class)->constructed (object); +} + +static void +goa_panel_accounts_model_class_init (GoaPanelAccountsModelClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = goa_panel_accounts_model_finalize; + gobject_class->constructed = goa_panel_accounts_model_constructed; + gobject_class->get_property = goa_panel_accounts_model_get_property; + gobject_class->set_property = goa_panel_accounts_model_set_property; + + /** + * GoaPanelAccountsModel:client: + * + * The #GoaClient used by the #GoaPanelAccountsModel instance. + */ + g_object_class_install_property (gobject_class, + PROP_CLIENT, + g_param_spec_object ("client", + "Client", + "The client used by the tree model", + GOA_TYPE_CLIENT, + G_PARAM_READABLE | + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * goa_panel_accounts_model_new: + * @client: A #GoaClient. + * + * Creates a new #GoaPanelAccountsModel for viewing the accounts known + * by @client. + * + * Returns: A #GoaPanelAccountsModel. Free with g_object_unref(). + */ +GoaPanelAccountsModel * +goa_panel_accounts_model_new (GoaClient *client) +{ + return GOA_PANEL_ACCOUNTS_MODEL (g_object_new (GOA_TYPE_PANEL_ACCOUNTS_MODEL, + "client", client, + NULL)); +} + +/** + * goa_panel_accounts_model_get_client: + * @model: A #GoaPanelAccountsModel. + * + * Gets the #GoaClient used by @model. + * + * Returns: (transfer none): A #GoaClient. Do not free, the object + * belongs to @model. + */ +GoaClient * +goa_panel_accounts_model_get_client (GoaPanelAccountsModel *model) +{ + g_return_val_if_fail (GOA_IS_PANEL_ACCOUNTS_MODEL (model), NULL); + return model->client; +} + +/** + * goa_panel_accounts_model_get_iter_for_object: + * @model: A #GoaPanelAccountsModel. + * @object: A #GoaObject. + * @iter: (out): Return location for #GtkTreeIter. + * + * Finds @model's row for @object. + * + * Returns: %TRUE if @iter was set, %FALSE if @object wasn't found. + */ +gboolean +goa_panel_accounts_model_get_iter_for_object (GoaPanelAccountsModel *model, + GoaObject *object, + GtkTreeIter *iter) +{ + g_return_val_if_fail (GOA_IS_PANEL_ACCOUNTS_MODEL (model), FALSE); + g_return_val_if_fail (GOA_IS_OBJECT (object), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + return find_iter_for_object (model, object, iter); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GoaObject *object; + GtkTreeIter iter; + gboolean found; +} FindIterData; + +static gboolean +find_iter_for_object_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + FindIterData *data = user_data; + GoaObject *iter_object; + + iter_object = NULL; + + gtk_tree_model_get (model, + iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &iter_object, + -1); + if (iter_object == NULL) + goto out; + + if (iter_object == data->object) + { + data->iter = *iter; + data->found = TRUE; + goto out; + } + + out: + if (iter_object != NULL) + g_object_unref (iter_object); + return data->found; +} + +static gboolean +find_iter_for_object (GoaPanelAccountsModel *model, + GoaObject *object, + GtkTreeIter *out_iter) +{ + FindIterData data; + memset (&data, 0, sizeof (data)); + data.object = object; + data.found = FALSE; + gtk_tree_model_foreach (GTK_TREE_MODEL (model), + find_iter_for_object_cb, + &data); + if (data.found) + { + if (out_iter != NULL) + *out_iter = data.iter; + } + return data.found; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +set_values (GoaPanelAccountsModel *model, + GoaObject *object, + GtkTreeIter *iter) +{ + GoaAccount *account; + GIcon *icon; + gchar *markup; + GError *error; + + account = goa_object_peek_account (object); + + error = NULL; + icon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error); + if (icon == NULL) + { + goa_warning ("Error creating GIcon for account: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + g_error_free (error); + } + + markup = g_strdup_printf ("%s\n%s", + goa_account_get_provider_name (account), + goa_account_get_presentation_identity (account)); + + gtk_list_store_set (GTK_LIST_STORE (model), + iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_SORT_KEY, goa_account_get_id (account), + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, object, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ATTENTION_NEEDED, goa_account_get_attention_needed (account), + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_MARKUP, markup, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ICON, icon, + -1); + + g_free (markup); + g_clear_object (&icon); +} + +static void +add_account (GoaPanelAccountsModel *model, + GoaObject *object) +{ + GtkTreeIter iter; + gtk_list_store_insert (GTK_LIST_STORE (model), + &iter, + G_MAXINT); /* position */ + set_values (model, object, &iter); +} + +static void +remove_account (GoaPanelAccountsModel *model, + GoaObject *object) +{ + GtkTreeIter iter; + if (!find_iter_for_object (model, object, &iter)) + { + goa_warning ("Error removing object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + } + else + { + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + } +} + +static void +update_account (GoaPanelAccountsModel *model, + GoaObject *object) +{ + GtkTreeIter iter; + if (!find_iter_for_object (model, object, &iter)) + { + goa_warning ("Error updating object %s - not in tree", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + } + else + { + set_values (model, object, &iter); + } +} + +static void +init_model (GoaPanelAccountsModel *model) +{ + GList *accounts; + GList *l; + + accounts = goa_client_get_accounts (model->client); + for (l = accounts; l != NULL; l = l->next) + { + GoaObject *object = GOA_OBJECT (l->data); + add_account (model, object); + } + g_list_foreach (accounts, (GFunc) g_object_unref, NULL); + g_list_free (accounts); +} + +static void +on_account_added (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (user_data); + add_account (model, object); +} + +static void +on_account_removed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (user_data); + remove_account (model, object); +} + +static void +on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanelAccountsModel *model = GOA_PANEL_ACCOUNTS_MODEL (user_data); + update_account (model, object); +} diff -Nru gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-panel.c gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-panel.c --- gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_new_goa_build.patch/panels/online-accounts/cc-online-accounts-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,795 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2011, 2012 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen + */ + +#include "config.h" + +#include +#include + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#include +#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE +#include + +#include "cc-online-accounts-panel.h" + +#include "cc-online-accounts-add-account-dialog.h" +#include "cc-online-accounts-model.h" + +typedef struct _GoaPanelClass GoaPanelClass; + +struct _GoaPanel +{ + CcPanel parent_instance; + + GtkBuilder *builder; + + GoaClient *client; + + GoaPanelAccountsModel *accounts_model; + + GtkWidget *toolbar; + GtkWidget *toolbar_add_button; + GtkWidget *toolbar_remove_button; + GtkWidget *accounts_treeview; + GtkWidget *accounts_vbox; +}; + +struct _GoaPanelClass +{ + CcPanelClass parent_class; +}; + +static void on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data); +static void on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data); + +static void on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data); + +static void on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data); +static void on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data); + +static void on_add_button_clicked (GtkButton *button, + gpointer user_data); + +static void on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data); + +static gboolean select_account_by_id (GoaPanel *panel, + const gchar *account_id); + +CC_PANEL_REGISTER (GoaPanel, goa_panel); + +enum { + PROP_0, + PROP_ARGV +}; + +static void +goa_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + case PROP_ARGV: + { + gchar **args; + + args = g_value_get_boxed (value); + + if (args != NULL && *args != '\0') + select_account_by_id (GOA_PANEL (object), args[0]); + return; + } + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +goa_panel_finalize (GObject *object) +{ + GoaPanel *panel = GOA_PANEL (object); + + if (panel->accounts_model != NULL) + g_clear_object (&panel->accounts_model); + + if (panel->client != NULL) + g_object_unref (panel->client); + g_object_unref (panel->builder); + + G_OBJECT_CLASS (goa_panel_parent_class)->finalize (object); +} + +static void +goa_panel_init (GoaPanel *panel) +{ + GtkWidget *button; + GtkWidget *w; + GError *error; + GtkStyleContext *context; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + + panel->builder = gtk_builder_new (); + error = NULL; + if (gtk_builder_add_from_file (panel->builder, + GNOMECC_UI_DIR "/online-accounts.ui", + &error) == 0) + { + goa_warning ("Error loading UI file: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + g_error_free (error); + goto out; + } + + panel->toolbar = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbar")); + panel->toolbar_add_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-add")); + g_signal_connect (panel->toolbar_add_button, + "clicked", + G_CALLBACK (on_toolbar_add_button_clicked), + panel); + panel->toolbar_remove_button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-toolbutton-remove")); + g_signal_connect (panel->toolbar_remove_button, + "clicked", + G_CALLBACK (on_toolbar_remove_button_clicked), + panel); + + context = gtk_widget_get_style_context (GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-scrolledwindow"))); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); + context = gtk_widget_get_style_context (panel->toolbar); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); + + panel->accounts_treeview = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-treeview")); + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + "changed", + G_CALLBACK (on_tree_view_selection_changed), + panel); + + button = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-button-add")); + g_signal_connect (button, + "clicked", + G_CALLBACK (on_add_button_clicked), + panel); + + panel->accounts_vbox = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-vbox")); + + /* TODO: probably want to avoid _sync() ... */ + error = NULL; + panel->client = goa_client_new_sync (NULL /* GCancellable */, &error); + if (panel->client == NULL) + { + goa_warning ("Error getting a GoaClient: %s (%s, %d)", + error->message, g_quark_to_string (error->domain), error->code); + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_set_sensitive (w, FALSE); + g_error_free (error); + goto out; + } + g_signal_connect (panel->client, + "account-changed", + G_CALLBACK (on_account_changed), + panel); + + panel->accounts_model = goa_panel_accounts_model_new (panel->client); + gtk_tree_view_set_model (GTK_TREE_VIEW (panel->accounts_treeview), GTK_TREE_MODEL (panel->accounts_model)); + g_signal_connect (panel->accounts_model, "row-deleted", G_CALLBACK (on_model_row_deleted), panel); + g_signal_connect (panel->accounts_model, "row-inserted", G_CALLBACK (on_model_row_inserted), panel); + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (panel->accounts_treeview), column); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "gicon", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "ellipsize", PANGO_ELLIPSIZE_END, + "ellipsize-set", TRUE, + "width-chars", 30, + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "markup", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_MARKUP, + NULL); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_end (column, renderer, FALSE); + g_object_set (G_OBJECT (renderer), + "icon-name", "dialog-error-symbolic", + NULL); + gtk_tree_view_column_set_attributes (column, + renderer, + "visible", GOA_PANEL_ACCOUNTS_MODEL_COLUMN_ATTENTION_NEEDED, + NULL); + + /* Select the first row, if any */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (panel->accounts_model), + &iter)) + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + &iter); + + out: + w = GTK_WIDGET (gtk_builder_get_object (panel->builder, "goa-top-widget")); + gtk_widget_reparent (w, GTK_WIDGET (panel)); + gtk_widget_show_all (w); +} + +static const char * +goa_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/accounts"; + else + return "help:gnome-help/accounts"; +} + +static void +goa_panel_class_init (GoaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = goa_panel_get_help_uri; + + object_class->set_property = goa_panel_set_property; + object_class->finalize = goa_panel_finalize; + + g_object_class_override_property (object_class, PROP_ARGV, "argv"); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +goa_panel_register (GIOModule *module) +{ + goa_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + GOA_TYPE_PANEL, + "online-accounts", + 0); +} + +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + goa_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +show_page (GoaPanel *panel, + gint page_num) +{ + GtkNotebook *notebook; + notebook = GTK_NOTEBOOK (gtk_builder_get_object (panel->builder, "accounts-notebook")); + gtk_notebook_set_current_page (notebook, page_num); +} + +static void +show_page_nothing_selected (GoaPanel *panel) +{ + GtkWidget *box; + GtkWidget *label; + + show_page (panel, 0); + + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, FALSE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_show (label); +} + +static void +on_info_bar_response (GtkInfoBar *info_bar, + gint response_id, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaProvider *provider; + const gchar *provider_type; + GoaAccount *account; + GoaObject *object; + GtkWindow *parent; + GError *error; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); + + error = NULL; + if (!goa_provider_refresh_account (provider, + panel->client, + object, + parent, + &error)) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error logging into the account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + g_object_unref (provider); + g_object_unref (object); + } +} + +static void +show_page_account (GoaPanel *panel, + GoaObject *object) +{ + GList *children; + GList *l; + GtkWidget *box; + GtkWidget *grid; + GtkWidget *left_grid; + GtkWidget *right_grid; + GtkWidget *bar; + GtkWidget *label; + GoaProvider *provider; + GoaAccount *account; + const gchar *provider_type; + + provider = NULL; + + show_page (panel, 1); + box = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-box")); + gtk_widget_set_sensitive (box, TRUE); + + label = GTK_WIDGET (gtk_builder_get_object (panel->builder, "accounts-tree-label")); + gtk_widget_hide (label); + + /* Out with the old */ + children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_vbox)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (panel->accounts_vbox), GTK_WIDGET (l->data)); + g_list_free (children); + + account = goa_object_peek_account (object); + provider_type = goa_account_get_provider_type (account); + provider = goa_provider_get_for_provider_type (provider_type); + + /* And in with the new */ + if (goa_account_get_attention_needed (account)) + { + bar = gtk_info_bar_new (); + label = gtk_label_new (_("Expired credentials. Please log in again.")); + gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label); + if (provider != NULL) + gtk_info_bar_add_button (GTK_INFO_BAR (bar), _("_Log In"), GTK_RESPONSE_OK); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), bar, FALSE, TRUE, 0); + g_signal_connect (bar, "response", G_CALLBACK (on_info_bar_response), panel); + } + + left_grid = gtk_grid_new (); + gtk_widget_set_halign (left_grid, GTK_ALIGN_END); + gtk_widget_set_hexpand (left_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (left_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (left_grid), 0); + + right_grid = gtk_grid_new (); + gtk_widget_set_hexpand (right_grid, TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (right_grid), GTK_ORIENTATION_VERTICAL); + gtk_grid_set_row_spacing (GTK_GRID (right_grid), 0); + + if (provider != NULL) + { + goa_provider_show_account (provider, + panel->client, + object, + GTK_BOX (panel->accounts_vbox), + GTK_GRID (left_grid), + GTK_GRID (right_grid)); + } + + grid = gtk_grid_new (); + gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL); + gtk_grid_set_column_spacing (GTK_GRID (grid), 12); + gtk_container_add (GTK_CONTAINER (grid), left_grid); + gtk_container_add (GTK_CONTAINER (grid), right_grid); + gtk_box_pack_start (GTK_BOX (panel->accounts_vbox), grid, FALSE, TRUE, 0); + + gtk_widget_show_all (panel->accounts_vbox); + + if (provider != NULL) + g_object_unref (provider); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +select_account_by_id (GoaPanel *panel, + const gchar *account_id) +{ + GoaObject *goa_object = NULL; + GtkTreeIter iter; + gboolean iter_set = FALSE; + + goa_object = goa_client_lookup_by_id (panel->client, account_id); + if (goa_object != NULL) + { + iter_set = goa_panel_accounts_model_get_iter_for_object (panel->accounts_model, + goa_object, + &iter); + g_object_unref (goa_object); + } + + if (iter_set) + { + GtkTreeView *tree_view; + GtkTreeSelection *selection; + + tree_view = GTK_TREE_VIEW (panel->accounts_treeview); + selection = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_select_iter (selection, &iter); + } + + return iter_set; +} + +static void +on_tree_view_selection_changed (GtkTreeSelection *selection, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GoaObject *object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + show_page_account (panel, object); + g_object_unref (object); + } + else + { + show_page_nothing_selected (panel); + } +} + +static void +on_account_changed (GoaClient *client, + GoaObject *object, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *selected_object; + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &selected_object, + -1); + if (selected_object == object) + show_page_account (panel, selected_object); + g_object_unref (selected_object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_model_row_changed (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GtkTreeSelection *selection = GTK_TREE_SELECTION (user_data); + + gtk_tree_selection_select_iter (selection, iter); + g_signal_handlers_disconnect_by_func (tree_model, G_CALLBACK (on_model_row_changed), user_data); +} + +static void +on_model_row_deleted (GtkTreeModel *tree_model, + GtkTreePath *path, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + GtkTreeSelection *selection; + + if (!gtk_tree_model_get_iter (tree_model, &iter, path)) + { + if (!gtk_tree_path_prev (path)) + return; + } + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + gtk_tree_selection_select_path (selection, path); +} + +static void +on_model_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)); + if (gtk_tree_selection_get_selected (selection, NULL, NULL)) + return; + + /* An empty row has been inserted and is going to be filled in, so + * we expect selection to stay valid. + */ + g_signal_connect (tree_model, "row-changed", G_CALLBACK (on_model_row_changed), selection); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GoaPanel *panel; +} AddAccountData; + +static void +get_all_providers_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + AddAccountData *data = user_data; + GtkWindow *parent; + GtkWidget *dialog; + gint response; + GList *providers; + GList *l; + GoaObject *object; + GError *error; + + providers = NULL; + + providers = NULL; + if (!goa_provider_get_all_finish (&providers, res, NULL)) + goto out; + + parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (data->panel)))); + + dialog = goa_panel_add_account_dialog_new (data->panel->client); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + for (l = providers; l != NULL; l = l->next) + { + GoaProvider *provider; + + provider = GOA_PROVIDER (l->data); + goa_panel_add_account_dialog_add_provider (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), provider); + } + + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + if (response != GTK_RESPONSE_OK) + { + gtk_widget_destroy (dialog); + goto out; + } + + error = NULL; + object = goa_panel_add_account_dialog_get_account (GOA_PANEL_ADD_ACCOUNT_DIALOG (dialog), &error); + gtk_widget_destroy (dialog); + + /* We might have an object even when error is set. + * eg., if we failed to store the credentials in the keyring. + */ + + if (object != NULL) + { + GtkTreeIter iter; + /* navigate to newly created object */ + if (goa_panel_accounts_model_get_iter_for_object (data->panel->accounts_model, + object, + &iter)) + { + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (data->panel->accounts_treeview)), + &iter); + } + g_object_unref (object); + } + + if (error != NULL) + { + if (!(error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)) + { + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error creating account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + + out: + g_list_foreach (providers, (GFunc) g_object_unref, NULL); + g_list_free (providers); + g_clear_object (&data->panel); + g_slice_free (AddAccountData, data); +} + +static void +add_account (GoaPanel *panel) +{ + AddAccountData *data; + + data = g_slice_new0 (AddAccountData); + data->panel = g_object_ref_sink (panel); + goa_provider_get_all (get_all_providers_cb, data); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_toolbar_add_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} + +static void +remove_account_cb (GoaAccount *account, + GAsyncResult *res, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GError *error; + + error = NULL; + if (!goa_account_call_remove_finish (account, res, &error)) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Error removing account")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", + error->message); + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } + g_object_unref (panel); +} + +static void +on_toolbar_remove_button_clicked (GtkToolButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (panel->accounts_treeview)), + NULL, + &iter)) + { + GoaObject *object; + GtkWidget *dialog; + gint response; + + gtk_tree_model_get (GTK_TREE_MODEL (panel->accounts_model), + &iter, + GOA_PANEL_ACCOUNTS_MODEL_COLUMN_OBJECT, &object, + -1); + + dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + _("Are you sure you want to remove the account?")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("This will not remove the account on the server.")); + gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Remove"), GTK_RESPONSE_OK); + gtk_widget_show_all (dialog); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (response == GTK_RESPONSE_OK) + { + goa_account_call_remove (goa_object_peek_account (object), + NULL, /* GCancellable */ + (GAsyncReadyCallback) remove_account_cb, + g_object_ref (panel)); + } + g_object_unref (object); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_add_button_clicked (GtkButton *button, + gpointer user_data) +{ + GoaPanel *panel = GOA_PANEL (user_data); + add_account (panel); +} diff -Nru gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/configure.ac gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/configure.ac --- gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,551 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +shell/libgnome-control-center.pc +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/bluetooth-properties.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/panels/info/cc-info-panel.c gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/panels/info/cc-info-panel.c --- gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/panels/info/cc-info-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_no_glxinfo.patch/panels/info/cc-info-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,2036 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "cc-info-panel.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "hostname-helper.h" +#include "gsd-disk-space-helper.h" + +/* Autorun options */ +#define PREF_MEDIA_AUTORUN_NEVER "autorun-never" +#define PREF_MEDIA_AUTORUN_X_CONTENT_START_APP "autorun-x-content-start-app" +#define PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE "autorun-x-content-ignore" +#define PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER "autorun-x-content-open-folder" + +#define CUSTOM_ITEM_ASK "cc-item-ask" +#define CUSTOM_ITEM_DO_NOTHING "cc-item-do-nothing" +#define CUSTOM_ITEM_OPEN_FOLDER "cc-item-open-folder" + +#define MEDIA_HANDLING_SCHEMA "org.gnome.desktop.media-handling" + +/* Session */ +#define GNOME_SESSION_MANAGER_SCHEMA "org.gnome.desktop.session" +#define KEY_SESSION_NAME "session-name" + +#define WID(w) (GtkWidget *) gtk_builder_get_object (self->priv->builder, w) + +CC_PANEL_REGISTER (CcInfoPanel, cc_info_panel) + +#define INFO_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_INFO_PANEL, CcInfoPanelPrivate)) + +typedef struct { + /* Will be one of the other two below, or "Unknown" */ + const char *hardware_string; + + char *xorg_vesa_hardware; + char *glx_renderer; +} GraphicsData; + +typedef enum { + PK_NOT_AVAILABLE, + UPDATES_AVAILABLE, + UPDATES_NOT_AVAILABLE, + CHECKING_UPDATES +} UpdatesState; + +typedef struct +{ + const char *content_type; + const char *label; + /* A pattern used to filter supported mime types + when changing preferred applications. NULL + means no other types should be changed */ + const char *extra_type_filter; +} DefaultAppData; + +struct _CcInfoPanelPrivate +{ + GtkBuilder *builder; + char *gnome_version; + char *gnome_distributor; + char *gnome_date; + UpdatesState updates_state; + gboolean is_fallback; + + /* Free space */ + GList *primary_mounts; + guint64 total_bytes; + GCancellable *cancellable; + + /* Media */ + GSettings *media_settings; + GtkWidget *other_application_combo; + + GDBusConnection *session_bus; + GDBusProxy *pk_proxy; + GDBusProxy *pk_transaction_proxy; + GDBusProxy *hostnamed_proxy; + GSettings *session_settings; + + GraphicsData *graphics_data; +}; + +static void get_primary_disc_info_start (CcInfoPanel *self); +static void refresh_update_button (CcInfoPanel *self); + +typedef struct +{ + char *major; + char *minor; + char *micro; + char *distributor; + char *date; + char **current; +} VersionData; + +static void +version_start_element_handler (GMarkupParseContext *ctx, + const char *element_name, + const char **attr_names, + const char **attr_values, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (g_str_equal (element_name, "platform")) + data->current = &data->major; + else if (g_str_equal (element_name, "minor")) + data->current = &data->minor; + else if (g_str_equal (element_name, "micro")) + data->current = &data->micro; + else if (g_str_equal (element_name, "distributor")) + data->current = &data->distributor; + else if (g_str_equal (element_name, "date")) + data->current = &data->date; + else + data->current = NULL; +} + +static void +version_end_element_handler (GMarkupParseContext *ctx, + const char *element_name, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + data->current = NULL; +} + +static void +version_text_handler (GMarkupParseContext *ctx, + const char *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + VersionData *data = user_data; + if (data->current != NULL) + *data->current = g_strstrip (g_strdup (text)); +} + +static gboolean +load_gnome_version (char **version, + char **distributor, + char **date) +{ + GMarkupParser version_parser = { + version_start_element_handler, + version_end_element_handler, + version_text_handler, + NULL, + NULL, + }; + GError *error; + GMarkupParseContext *ctx; + char *contents; + gsize length; + VersionData *data; + gboolean ret; + + ret = FALSE; + + error = NULL; + if (!g_file_get_contents (DATADIR "/gnome/gnome-version.xml", + &contents, + &length, + &error)) + return FALSE; + + data = g_new0 (VersionData, 1); + ctx = g_markup_parse_context_new (&version_parser, 0, data, NULL); + + if (!g_markup_parse_context_parse (ctx, contents, length, &error)) + { + g_warning ("Invalid version file: '%s'", error->message); + } + else + { + if (version != NULL) + *version = g_strdup_printf ("%s.%s.%s", data->major, data->minor, data->micro); + if (distributor != NULL) + *distributor = g_strdup (data->distributor); + if (date != NULL) + *date = g_strdup (data->date); + + ret = TRUE; + } + + g_markup_parse_context_free (ctx); + g_free (data->major); + g_free (data->minor); + g_free (data->micro); + g_free (data->distributor); + g_free (data->date); + g_free (data); + g_free (contents); + + return ret; +}; + +typedef struct +{ + char *regex; + char *replacement; +} ReplaceStrings; + +static char * +prettify_info (const char *info) +{ + char *pretty; + int i; + static const ReplaceStrings rs[] = { + { "Mesa DRI ", ""}, + { "Intel[(]R[)]", "Intel\302\256"}, + { "Core[(]TM[)]", "Core\342\204\242"}, + { "Atom[(]TM[)]", "Atom\342\204\242"}, + { "Graphics Controller", "Graphics"}, + }; + + pretty = g_markup_escape_text (info, -1); + + for (i = 0; i < G_N_ELEMENTS (rs); i++) + { + GError *error; + GRegex *re; + char *new; + + error = NULL; + + re = g_regex_new (rs[i].regex, 0, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + continue; + } + + new = g_regex_replace_literal (re, + pretty, + -1, + 0, + rs[i].replacement, + 0, + &error); + + g_regex_unref (re); + + if (error != NULL) + { + g_warning ("Error replacing %s: %s", rs[i].regex, error->message); + g_error_free (error); + continue; + } + + g_free (pretty); + pretty = new; + } + + return pretty; +} + +static void +graphics_data_free (GraphicsData *gdata) +{ + g_free (gdata->xorg_vesa_hardware); + g_free (gdata->glx_renderer); + g_slice_free (GraphicsData, gdata); +} + +static char * +get_graphics_data_glx_renderer (void) +{ + GError *error; + GRegex *re; + GMatchInfo *match_info; + char *output; + char *result; + GString *info; + + info = g_string_new (NULL); + + error = NULL; + g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error); + if (error != NULL) + { + g_warning ("Unable to get graphics info: %s", error->message); + g_error_free (error); + return NULL; + } + + re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + goto out; + } + + g_regex_match (re, output, 0, &match_info); + while (g_match_info_matches (match_info)) + { + char *device; + + device = g_match_info_fetch (match_info, 1); + g_string_append_printf (info, "%s ", device); + g_free (device); + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + g_regex_unref (re); + + out: + g_free (output); + result = prettify_info (info->str); + g_string_free (info, TRUE); + + return result; +} + +static char * +get_graphics_data_xorg_vesa_hardware (void) +{ + char *display_num; + char *log_path; + char *log_contents; + gsize log_len; + GError *error = NULL; + GRegex *re; + GMatchInfo *match; + char *result = NULL; + + { + const char *display; + + display = g_getenv ("DISPLAY"); + if (!display) + return NULL; + + re = g_regex_new ("^:([0-9]+)", 0, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, display, 0, &match); + + if (!g_match_info_matches (match)) + { + g_regex_unref (re); + g_match_info_free (match); + return NULL; + } + + display_num = g_match_info_fetch (match, 1); + + g_regex_unref (re); + re = NULL; + g_match_info_free (match); + match = NULL; + } + + log_path = g_strdup_printf ("/var/log/Xorg.%s.log", display_num); + g_free (display_num); + log_contents = NULL; + g_file_get_contents (log_path, &log_contents, &log_len, &error); + g_free (log_path); + if (!log_contents) + return NULL; + + re = g_regex_new ("VESA VBE OEM Product: (.*)$", G_REGEX_MULTILINE, 0, NULL); + g_assert (re != NULL); + + g_regex_match (re, log_contents, 0, &match); + if (g_match_info_matches (match)) + { + char *tmp; + char *pretty_tmp; + tmp = g_match_info_fetch (match, 1); + pretty_tmp = prettify_info (tmp); + g_free (tmp); + /* Translators: VESA is an techncial acronym, don't translate it. */ + result = g_strdup_printf (_("VESA: %s"), pretty_tmp); + g_free (pretty_tmp); + } + g_match_info_free (match); + g_regex_unref (re); + + return result; +} + +static GraphicsData * +get_graphics_data (void) +{ + GraphicsData *result; + + result = g_slice_new0 (GraphicsData); + + result->glx_renderer = get_graphics_data_glx_renderer (); + result->xorg_vesa_hardware = get_graphics_data_xorg_vesa_hardware (); + + if (result->xorg_vesa_hardware != NULL) + result->hardware_string = result->xorg_vesa_hardware; + else if (result->glx_renderer != NULL) + result->hardware_string = result->glx_renderer; + else + result->hardware_string = _("Unknown"); + + return result; +} + +static gboolean +get_current_is_fallback (CcInfoPanel *self) +{ + GError *error; + GVariant *reply; + GVariant *reply_str; + gboolean is_fallback; + + error = NULL; + if (!(reply = g_dbus_connection_call_sync (self->priv->session_bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", "org.gnome.SessionManager", "session-name"), + (GVariantType*)"(v)", + 0, + -1, + NULL, &error))) + { + g_warning ("Failed to get fallback mode: %s", error->message); + g_clear_error (&error); + return FALSE; + } + + g_variant_get (reply, "(v)", &reply_str); + is_fallback = g_strcmp0 ("gnome-fallback", g_variant_get_string (reply_str, NULL)) == 0; + g_variant_unref (reply_str); + g_variant_unref (reply); + + return is_fallback; +} + +static void +cc_info_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_info_panel_dispose (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->pk_proxy != NULL) + { + g_object_unref (priv->pk_proxy); + priv->pk_proxy = NULL; + } + + if (priv->pk_transaction_proxy != NULL) + { + g_object_unref (priv->pk_transaction_proxy); + priv->pk_transaction_proxy = NULL; + } + + if (priv->graphics_data != NULL) + { + graphics_data_free (priv->graphics_data); + priv->graphics_data = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->dispose (object); +} + +static void +cc_info_panel_finalize (GObject *object) +{ + CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv; + + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + priv->cancellable = NULL; + } + g_free (priv->gnome_version); + g_free (priv->gnome_date); + g_free (priv->gnome_distributor); + + if (priv->hostnamed_proxy != NULL) + { + g_object_unref (priv->hostnamed_proxy); + priv->hostnamed_proxy = NULL; + } + + if (priv->media_settings != NULL) + { + g_object_unref (priv->media_settings); + priv->media_settings = NULL; + } + + if (priv->session_settings != NULL) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + + G_OBJECT_CLASS (cc_info_panel_parent_class)->finalize (object); +} + +static void +cc_info_panel_class_init (CcInfoPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcInfoPanelPrivate)); + + object_class->get_property = cc_info_panel_get_property; + object_class->set_property = cc_info_panel_set_property; + object_class->dispose = cc_info_panel_dispose; + object_class->finalize = cc_info_panel_finalize; +} + +static char * +get_os_type (void) +{ + int bits; + + if (GLIB_SIZEOF_VOID_P == 8) + bits = 64; + else + bits = 32; + + /* translators: This is the type of architecture, for example: + * "64-bit" or "32-bit" */ + return g_strdup_printf (_("%d-bit"), bits); +} + +static void +query_done (GFile *file, + GAsyncResult *res, + CcInfoPanel *self) +{ + GFileInfo *info; + GError *error = NULL; + + self->priv->cancellable = NULL; + info = g_file_query_filesystem_info_finish (file, res, &error); + if (info != NULL) + { + self->priv->total_bytes += g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE); + g_object_unref (info); + } + else + { + char *path; + path = g_file_get_path (file); + g_warning ("Failed to get filesystem free space for '%s': %s", path, error->message); + g_free (path); + g_error_free (error); + } + + /* And onto the next element */ + get_primary_disc_info_start (self); +} + +static void +get_primary_disc_info_start (CcInfoPanel *self) +{ + GUnixMountEntry *mount; + GFile *file; + + if (self->priv->primary_mounts == NULL) + { + char *size; + GtkWidget *widget; + + size = g_format_size (self->priv->total_bytes); + widget = WID ("disk_label"); + gtk_label_set_text (GTK_LABEL (widget), size); + g_free (size); + + return; + } + + mount = self->priv->primary_mounts->data; + self->priv->primary_mounts = g_list_remove (self->priv->primary_mounts, mount); + file = g_file_new_for_path (g_unix_mount_get_mount_path (mount)); + g_unix_mount_free (mount); + + self->priv->cancellable = g_cancellable_new (); + + g_file_query_filesystem_info_async (file, + G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, + 0, + self->priv->cancellable, + (GAsyncReadyCallback) query_done, + self); + g_object_unref (file); +} + +static void +get_primary_disc_info (CcInfoPanel *self) +{ + GList *points; + GList *p; + + points = g_unix_mount_points_get (NULL); + for (p = points; p != NULL; p = p->next) + { + GUnixMountEntry *mount = p->data; + const char *mount_path; + + mount_path = g_unix_mount_get_mount_path (mount); + + if (gsd_should_ignore_unix_mount (mount) || + gsd_is_removable_mount (mount) || + g_str_has_prefix (mount_path, "/media/") || + g_str_has_prefix (mount_path, g_get_home_dir ())) + { + g_unix_mount_free (mount); + continue; + } + + self->priv->primary_mounts = g_list_prepend (self->priv->primary_mounts, mount); + } + g_list_free (points); + + get_primary_disc_info_start (self); +} + +static char * +remove_duplicate_whitespace (const char *old) +{ + char *new; + GRegex *re; + GError *error; + + error = NULL; + re = g_regex_new ("[ \t\n\r]+", G_REGEX_MULTILINE, 0, &error); + if (re == NULL) + { + g_warning ("Error building regex: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + new = g_regex_replace (re, + old, + -1, + 0, + " ", + 0, + &error); + g_regex_unref (re); + if (new == NULL) + { + g_warning ("Error replacing string: %s", error->message); + g_error_free (error); + return g_strdup (old); + } + + return new; +} + + +static char * +get_cpu_info (const glibtop_sysinfo *info) +{ + GHashTable *counts; + GString *cpu; + char *ret; + GHashTableIter iter; + gpointer key, value; + int i; + int j; + + counts = g_hash_table_new (g_str_hash, g_str_equal); + + /* count duplicates */ + for (i = 0; i != info->ncpu; ++i) + { + const char * const keys[] = { "model name", "cpu" }; + char *model; + int *count; + + model = NULL; + + for (j = 0; model == NULL && j != G_N_ELEMENTS (keys); ++j) + { + model = g_hash_table_lookup (info->cpuinfo[i].values, + keys[j]); + } + + if (model == NULL) + model = _("Unknown model"); + + count = g_hash_table_lookup (counts, model); + if (count == NULL) + g_hash_table_insert (counts, model, GINT_TO_POINTER (1)); + else + g_hash_table_replace (counts, model, GINT_TO_POINTER (GPOINTER_TO_INT (count) + 1)); + } + + cpu = g_string_new (NULL); + g_hash_table_iter_init (&iter, counts); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + char *stripped; + int count; + + count = GPOINTER_TO_INT (value); + stripped = remove_duplicate_whitespace ((const char *)key); + if (count > 1) + g_string_append_printf (cpu, "%s \303\227 %d ", stripped, count); + else + g_string_append_printf (cpu, "%s ", stripped); + g_free (stripped); + } + + g_hash_table_destroy (counts); + + ret = prettify_info (cpu->str); + g_string_free (cpu, TRUE); + + return ret; +} + +static void +on_section_changed (GtkTreeSelection *selection, + gpointer data) +{ + CcInfoPanel *self = CC_INFO_PANEL (data); + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gint *indices; + int index; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + + indices = gtk_tree_path_get_indices (path); + index = indices[0]; + + if (index >= 0) + { + g_object_set (G_OBJECT (WID ("notebook")), + "page", index, NULL); + } + + gtk_tree_path_free (path); +} + +static gboolean +switch_fallback_get_mapping (GValue *value, + GVariant *variant, + gpointer data) +{ + const char *setting; + + setting = g_variant_get_string (variant, NULL); + g_value_set_boolean (value, strcmp (setting, "gnome") != 0); + return TRUE; +} + +static void +toggle_fallback_warning_label (CcInfoPanel *self, + gboolean visible) +{ + GtkWidget *widget; + const char *text; + + widget = WID ("graphics_logout_warning_label"); + + if (self->priv->is_fallback) + text = _("The next login will attempt to use the standard experience."); + else + text = _("The next login will use the fallback mode intended for unsupported graphics hardware."); + + gtk_label_set_text (GTK_LABEL (widget), text); + + if (visible) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); +} + +static GVariant * +switch_fallback_set_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer data) +{ + CcInfoPanel *self = data; + gboolean is_set; + + is_set = g_value_get_boolean (value); + if (is_set != self->priv->is_fallback) + toggle_fallback_warning_label (self, TRUE); + else + toggle_fallback_warning_label (self, FALSE); + + return g_variant_new_string (is_set ? "gnome-fallback" : "gnome"); +} + +static void +info_panel_setup_graphics (CcInfoPanel *self) +{ + GtkWidget *widget; + GtkSwitch *sw; + char *text; + + widget = WID ("graphics_driver_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + self->priv->is_fallback = get_current_is_fallback (self); + if (self->priv->is_fallback) + { + /* translators: The hardware is not able to run GNOME 3's + * shell, so we use the GNOME "Fallback" session */ + text = g_strdup (C_("Experience", "Fallback")); + } + else + { + /* translators: The hardware is able to run GNOME 3's + * shell, also called "Standard" experience */ + text = g_strdup (C_("Experience", "Standard")); + } + widget = WID ("graphics_experience_label"); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("graphics_fallback_switch_box"); + sw = GTK_SWITCH (gtk_switch_new ()); + g_settings_bind_with_mapping (self->priv->session_settings, KEY_SESSION_NAME, + sw, "active", 0, + switch_fallback_get_mapping, + switch_fallback_set_mapping, self, NULL); + gtk_box_pack_start (GTK_BOX (widget), GTK_WIDGET (sw), FALSE, FALSE, 0); + gtk_widget_show_all (GTK_WIDGET (sw)); + widget = WID ("fallback-label"); + gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (sw)); +} + +static void +default_app_changed (GtkAppChooserButton *button, + CcInfoPanel *self) +{ + GAppInfo *info; + GError *error = NULL; + DefaultAppData *app_data; + int i; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (button)); + app_data = g_object_get_data (G_OBJECT (button), "cc-default-app-data"); + + if (g_app_info_set_as_default_for_type (info, app_data->content_type, &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for '%s': %s", + g_app_info_get_name (info), app_data->content_type, error->message); + g_error_free (error); + error = NULL; + } + + if (app_data->extra_type_filter) + { + const char *const *mime_types; + GPatternSpec *pattern; + + pattern = g_pattern_spec_new (app_data->extra_type_filter); + mime_types = g_app_info_get_supported_types (info); + + for (i = 0; mime_types[i]; i++) + { + if (!g_pattern_match_string (pattern, mime_types[i])) + continue; + + if (g_app_info_set_as_default_for_type (info, mime_types[i], &error) == FALSE) + { + g_warning ("Failed to set '%s' as the default application for secondary " + "content type '%s': %s", + g_app_info_get_name (info), mime_types[i], error->message); + g_error_free (error); + } + } + + g_pattern_spec_free (pattern); + } + + g_object_unref (info); +} + +static void +info_panel_setup_default_app (CcInfoPanel *self, + DefaultAppData *data, + guint left_attach, + guint right_attach, + guint top_attach, + guint bottom_attach) +{ + GtkWidget *button; + GtkWidget *table; + GtkWidget *label; + + table = WID ("default_apps_table"); + + button = gtk_app_chooser_button_new (data->content_type); + g_object_set_data (G_OBJECT (button), "cc-default-app-data", data); + + gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (button), TRUE); + gtk_table_attach (GTK_TABLE (table), button, + left_attach, right_attach, + top_attach, bottom_attach, GTK_FILL, 0, 0, 0); + g_signal_connect (G_OBJECT (button), "changed", + G_CALLBACK (default_app_changed), self); + gtk_widget_show (button); + + label = WID(data->label); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), button); +} + +static DefaultAppData preferred_app_infos[] = { + /* for web, we need to support text/html, + application/xhtml+xml and x-scheme-handler/https, + hence the "*" pattern + */ + { "x-scheme-handler/http", "web-label", "*" }, + { "x-scheme-handler/mailto", "mail-label", NULL }, + { "text/calendar", "calendar-label", NULL }, + { "audio/x-vorbis+ogg", "music-label", "audio/*" }, + { "video/x-ogm+ogg", "video-label", "video/*" }, + { "image/jpeg", "photos-label", "image/*" } +}; + +static void +info_panel_setup_default_apps (CcInfoPanel *self) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(preferred_app_infos); i++) + { + info_panel_setup_default_app (self, &preferred_app_infos[i], + 1, 2, i, i+1); + } +} + +static char ** +remove_elem_from_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + if (g_strcmp0 (v[idx], s) == 0) { + continue; + } + + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static char ** +add_elem_to_str_array (char **v, + const char *s) +{ + GPtrArray *array; + guint idx; + + array = g_ptr_array_new (); + + for (idx = 0; v[idx] != NULL; idx++) { + g_ptr_array_add (array, v[idx]); + } + + g_ptr_array_add (array, g_strdup (s)); + g_ptr_array_add (array, NULL); + + g_free (v); + + return (char **) g_ptr_array_free (array, FALSE); +} + +static int +media_panel_g_strv_find (char **strv, + const char *find_me) +{ + guint index; + + g_return_val_if_fail (find_me != NULL, -1); + + for (index = 0; strv[index] != NULL; ++index) { + if (g_strcmp0 (strv[index], find_me) == 0) { + return index; + } + } + + return -1; +} + +static void +autorun_get_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean *pref_start_app, + gboolean *pref_ignore, + gboolean *pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_return_if_fail (pref_start_app != NULL); + g_return_if_fail (pref_ignore != NULL); + g_return_if_fail (pref_open_folder != NULL); + + *pref_start_app = FALSE; + *pref_ignore = FALSE; + *pref_open_folder = FALSE; + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + if (x_content_start_app != NULL) { + *pref_start_app = media_panel_g_strv_find (x_content_start_app, x_content_type) != -1; + } + if (x_content_ignore != NULL) { + *pref_ignore = media_panel_g_strv_find (x_content_ignore, x_content_type) != -1; + } + if (x_content_open_folder != NULL) { + *pref_open_folder = media_panel_g_strv_find (x_content_open_folder, x_content_type) != -1; + } + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + g_strfreev (x_content_open_folder); +} + +static void +autorun_set_preferences (CcInfoPanel *self, + const char *x_content_type, + gboolean pref_start_app, + gboolean pref_ignore, + gboolean pref_open_folder) +{ + char **x_content_start_app; + char **x_content_ignore; + char **x_content_open_folder; + + g_assert (x_content_type != NULL); + + x_content_start_app = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP); + x_content_ignore = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE); + x_content_open_folder = g_settings_get_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER); + + x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type); + if (pref_start_app) { + x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app); + + x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type); + if (pref_ignore) { + x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore); + + x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type); + if (pref_open_folder) { + x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type); + } + g_settings_set_strv (self->priv->media_settings, + PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder); + + g_strfreev (x_content_open_folder); + g_strfreev (x_content_ignore); + g_strfreev (x_content_start_app); + +} + +static void +custom_item_activated_cb (GtkAppChooserButton *button, + const gchar *item, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button)); + + if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, FALSE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) { + autorun_set_preferences (self, content_type, + FALSE, FALSE, TRUE); + } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) { + autorun_set_preferences (self, content_type, + FALSE, TRUE, FALSE); + } + + g_free (content_type); +} + +static void +combo_box_changed_cb (GtkComboBox *combo_box, + gpointer user_data) +{ + CcInfoPanel *self = user_data; + GAppInfo *info; + gchar *content_type; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + if (info == NULL) + return; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (combo_box)); + autorun_set_preferences (self, content_type, + TRUE, FALSE, FALSE); + g_app_info_set_as_default_for_type (info, content_type, NULL); + + g_object_unref (info); + g_free (content_type); +} + +static void +prepare_combo_box (CcInfoPanel *self, + GtkWidget *combo_box, + const gchar *heading) +{ + GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box); + gboolean pref_ask; + gboolean pref_start_app; + gboolean pref_ignore; + gboolean pref_open_folder; + GAppInfo *info; + gchar *content_type; + + content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser)); + + /* fetch preferences for this content type */ + autorun_get_preferences (self, content_type, + &pref_start_app, &pref_ignore, &pref_open_folder); + pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); + + /* append the separator only if we have >= 1 apps in the chooser */ + if (info != NULL) { + gtk_app_chooser_button_append_separator (app_chooser); + g_object_unref (info); + } + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK, + _("Ask what to do"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING, + _("Do nothing"), + NULL); + + gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER, + _("Open folder"), + NULL); + + gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE); + gtk_app_chooser_button_set_heading (app_chooser, _(heading)); + + if (pref_ask) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK); + } else if (pref_ignore) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING); + } else if (pref_open_folder) { + gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER); + } + + g_signal_connect (app_chooser, "changed", + G_CALLBACK (combo_box_changed_cb), self); + g_signal_connect (app_chooser, "custom-item-activated", + G_CALLBACK (custom_item_activated_cb), self); + + g_free (content_type); +} + +static void +other_type_combo_box_changed (GtkComboBox *combo_box, + CcInfoPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + char *x_content_type; + GtkWidget *action_container; + GtkWidget *action_label; + + x_content_type = NULL; + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) { + return; + } + + model = gtk_combo_box_get_model (combo_box); + if (model == NULL) { + return; + } + + gtk_tree_model_get (model, &iter, + 1, &x_content_type, + -1); + + action_container = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_container")); + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + } + + self->priv->other_application_combo = gtk_app_chooser_button_new (x_content_type); + gtk_box_pack_start (GTK_BOX (action_container), self->priv->other_application_combo, TRUE, TRUE, 0); + prepare_combo_box (self, self->priv->other_application_combo, NULL); + gtk_widget_show (self->priv->other_application_combo); + + action_label = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "media_other_action_label")); + + gtk_label_set_mnemonic_widget (GTK_LABEL (action_label), self->priv->other_application_combo); + + g_free (x_content_type); +} + +static void +on_extra_options_dialog_response (GtkWidget *dialog, + int response, + CcInfoPanel *self) +{ + gtk_widget_hide (dialog); + + if (self->priv->other_application_combo != NULL) { + gtk_widget_destroy (self->priv->other_application_combo); + self->priv->other_application_combo = NULL; + } +} + +static void +on_extra_options_button_clicked (GtkWidget *button, + CcInfoPanel *self) +{ + GtkWidget *dialog; + GtkWidget *combo_box; + + dialog = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "extra_options_dialog")); + combo_box = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_other_type_combobox")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Other Media")); + g_signal_connect (dialog, + "response", + G_CALLBACK (on_extra_options_dialog_response), + self); + g_signal_connect (dialog, + "delete-event", + G_CALLBACK (gtk_widget_hide_on_delete), + NULL); + /* update other_application_combo */ + other_type_combo_box_changed (GTK_COMBO_BOX (combo_box), self); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +info_panel_setup_media (CcInfoPanel *self) +{ + guint n; + GList *l, *content_types; + GtkWidget *other_type_combo_box; + GtkWidget *extras_button; + GtkListStore *other_type_list_store; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkBuilder *builder = self->priv->builder; + + struct { + const gchar *widget_name; + const gchar *content_type; + const gchar *heading; + } const defs[] = { + { "media_audio_cdda_combobox", "x-content/audio-cdda", N_("Select an application for audio CDs") }, + { "media_video_dvd_combobox", "x-content/video-dvd", N_("Select an application for video DVDs") }, + { "media_music_player_combobox", "x-content/audio-player", N_("Select an application to run when a music player is connected") }, + { "media_dcf_combobox", "x-content/image-dcf", N_("Select an application to run when a camera is connected") }, + { "media_software_combobox", "x-content/unix-software", N_("Select an application for software CDs") }, + }; + + struct { + const gchar *content_type; + const gchar *description; + } const other_defs[] = { + /* translators: these strings are duplicates of shared-mime-info + * strings, just here to fix capitalization of the English originals. + * If the shared-mime-info translation works for your language, + * simply leave these untranslated. + */ + { "x-content/audio-dvd", N_("audio DVD") }, + { "x-content/blank-bd", N_("blank Blu-ray disc") }, + { "x-content/blank-cd", N_("blank CD disc") }, + { "x-content/blank-dvd", N_("blank DVD disc") }, + { "x-content/blank-hddvd", N_("blank HD DVD disc") }, + { "x-content/video-bluray", N_("Blu-ray video disc") }, + { "x-content/ebook-reader", N_("e-book reader") }, + { "x-content/video-hddvd", N_("HD DVD video disc") }, + { "x-content/image-picturecd", N_("Picture CD") }, + { "x-content/video-svcd", N_("Super Video CD") }, + { "x-content/video-vcd", N_("Video CD") }, + { "x-content/win32-software", N_("Windows software") }, + { "x-content/software", N_("Software") } + }; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + prepare_combo_box (self, + GTK_WIDGET (gtk_builder_get_object (builder, defs[n].widget_name)), + defs[n].heading); + } + + other_type_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "media_other_type_combobox")); + + other_type_list_store = gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (other_type_list_store), + 1, GTK_SORT_ASCENDING); + + + content_types = g_content_types_get_registered (); + + for (l = content_types; l != NULL; l = l->next) { + char *content_type = l->data; + char *description = NULL; + + if (!g_str_has_prefix (content_type, "x-content/")) + continue; + + for (n = 0; n < G_N_ELEMENTS (defs); n++) { + if (g_content_type_is_a (content_type, defs[n].content_type)) { + goto skip; + } + } + + for (n = 0; n < G_N_ELEMENTS (other_defs); n++) { + if (strcmp (content_type, other_defs[n].content_type) == 0) { + const gchar *s = other_defs[n].description; + if (s == _(s)) + description = g_content_type_get_description (content_type); + else + description = g_strdup (_(s)); + + break; + } + } + + if (description == NULL) { + g_debug ("Content type '%s' is missing from the info panel", content_type); + description = g_content_type_get_description (content_type); + } + + gtk_list_store_append (other_type_list_store, &iter); + + gtk_list_store_set (other_type_list_store, &iter, + 0, description, + 1, content_type, + -1); + g_free (description); + skip: + ; + } + + g_list_free_full (content_types, g_free); + + gtk_combo_box_set_model (GTK_COMBO_BOX (other_type_combo_box), + GTK_TREE_MODEL (other_type_list_store)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (other_type_combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (other_type_combo_box), renderer, + "text", 0, + NULL); + + g_signal_connect (other_type_combo_box, + "changed", + G_CALLBACK (other_type_combo_box_changed), + self); + + gtk_combo_box_set_active (GTK_COMBO_BOX (other_type_combo_box), 0); + + extras_button = GTK_WIDGET (gtk_builder_get_object (builder, "extra_options_button")); + g_signal_connect (extras_button, + "clicked", + G_CALLBACK (on_extra_options_button_clicked), + self); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + gtk_builder_get_object (self->priv->builder, "media_autorun_never_checkbutton"), + "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->priv->media_settings, + PREF_MEDIA_AUTORUN_NEVER, + GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_handling_vbox")), + "sensitive", + G_SETTINGS_BIND_INVERT_BOOLEAN); +} + +static void +info_panel_setup_selector (CcInfoPanel *self) +{ + GtkTreeView *view; + GtkListStore *model; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeIter iter; + int section_name_column = 0; + + view = GTK_TREE_VIEW (WID ("overview_treeview")); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + + model = gtk_list_store_new (1, G_TYPE_STRING); + gtk_tree_view_set_model (view, GTK_TREE_MODEL (model)); + g_object_unref (model); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_renderer_set_padding (renderer, 4, 4); + g_object_set (renderer, + "width-chars", 20, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + column = gtk_tree_view_column_new_with_attributes (_("Section"), + renderer, + "text", section_name_column, + NULL); + gtk_tree_view_append_column (view, column); + + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Overview"), + -1); + gtk_tree_selection_select_iter (selection, &iter); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Default Applications"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Removable Media"), + -1); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, section_name_column, + _("Graphics"), + -1); + + g_signal_connect (selection, "changed", + G_CALLBACK (on_section_changed), self); + on_section_changed (selection, self); + + gtk_widget_show_all (GTK_WIDGET (view)); +} + +static char * +get_hostname_property (CcInfoPanel *self, + const char *property) +{ + GVariant *variant; + char *str; + + variant = g_dbus_proxy_get_cached_property (self->priv->hostnamed_proxy, + property); + if (!variant) + { + GError *error = NULL; + GVariant *inner; + + /* Work around systemd-hostname not sending us back + * the property value when changing values */ + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", "org.freedesktop.hostname1", property), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (variant == NULL) + { + g_warning ("Failed to get property '%s': %s", property, error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (variant, "(v)", &inner); + str = g_variant_dup_string (inner, NULL); + g_variant_unref (variant); + } + else + { + str = g_variant_dup_string (variant, NULL); + g_variant_unref (variant); + } + + return str; +} + +static char * +info_panel_get_hostname (CcInfoPanel *self) +{ + char *str; + + str = get_hostname_property (self, "PrettyHostname"); + + /* Empty strings means that we need to fallback */ + if (str != NULL && + *str == '\0') + { + g_free (str); + str = get_hostname_property (self, "Hostname"); + } + + return str; +} + +static void +info_panel_set_hostname (CcInfoPanel *self, + const char *text) +{ + char *hostname; + GVariant *variant; + GError *error = NULL; + + g_debug ("Setting PrettyHostname to '%s'", text); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetPrettyHostname", + g_variant_new ("(sb)", text, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set PrettyHostname: %s", error->message); + g_error_free (error); + error = NULL; + } + else + { + g_variant_unref (variant); + } + + /* Set the static hostname */ + hostname = pretty_hostname_to_static (text, FALSE); + g_assert (hostname); + + g_debug ("Setting StaticHostname to '%s'", hostname); + variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (variant == NULL) + { + g_warning ("Could not set StaticHostname: %s", error->message); + g_error_free (error); + } + else + { + g_variant_unref (variant); + } + g_free (hostname); +} + +static void +text_changed_cb (GtkEntry *entry, + CcInfoPanel *self) +{ + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + info_panel_set_hostname (self, text); +} + +static void +info_panel_setup_hostname (CcInfoPanel *self, + GPermission *permission) +{ + char *str; + GtkWidget *entry; + GError *error = NULL; + + if (permission == NULL) + { + g_debug ("Will not show hostname, hostnamed not installed"); + return; + } + + entry = WID ("name_entry"); + + if (g_permission_get_allowed (permission) != FALSE) + { + g_debug ("Not allowed to change the hostname"); + gtk_widget_set_sensitive (entry, TRUE); + } + + self->priv->hostnamed_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + NULL, + &error); + + /* This could only happen if the policy file was installed + * but not hostnamed, which points to a system bug */ + if (self->priv->hostnamed_proxy == NULL) + { + g_debug ("Couldn't get hostnamed to start, bailing: %s", error->message); + g_error_free (error); + return; + } + + gtk_widget_show (WID ("label4")); + gtk_widget_show (entry); + + str = info_panel_get_hostname (self); + if (str != NULL) + gtk_entry_set_text (GTK_ENTRY (entry), str); + else + gtk_entry_set_text (GTK_ENTRY (entry), ""); + g_free (str); + + g_signal_connect (G_OBJECT (entry), "changed", + G_CALLBACK (text_changed_cb), self); +} + +static void +info_panel_setup_overview (CcInfoPanel *self) +{ + GtkWidget *widget; + gboolean res; + glibtop_mem mem; + const glibtop_sysinfo *info; + char *text; + GPermission *permission; + + permission = polkit_permission_new_sync ("org.freedesktop.hostname1.set-static-hostname", NULL, NULL, NULL); + /* Is hostnamed installed? */ + info_panel_setup_hostname (self, permission); + + res = load_gnome_version (&self->priv->gnome_version, + &self->priv->gnome_distributor, + &self->priv->gnome_date); + if (res) + { + widget = WID ("version_label"); + text = g_strdup_printf (_("Version %s"), self->priv->gnome_version); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); + } + + gtk_widget_hide (WID ("version_label")); + + glibtop_get_mem (&mem); + text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS); + widget = WID ("memory_label"); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + info = glibtop_get_sysinfo (); + + widget = WID ("processor_label"); + text = get_cpu_info (info); + gtk_label_set_markup (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + widget = WID ("os_type_label"); + text = get_os_type (); + gtk_label_set_text (GTK_LABEL (widget), text ? text : ""); + g_free (text); + + get_primary_disc_info (self); + + widget = WID ("graphics_label"); + gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string); + + widget = WID ("info_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + + refresh_update_button (self); +} + +static void +refresh_update_button (CcInfoPanel *self) +{ + GtkWidget *widget; + + widget = WID ("updates_button"); + if (widget == NULL) + return; + + switch (self->priv->updates_state) + { + case PK_NOT_AVAILABLE: + gtk_widget_set_visible (widget, FALSE); + break; + case UPDATES_AVAILABLE: + gtk_widget_set_sensitive (widget, TRUE); + gtk_button_set_label (GTK_BUTTON (widget), _("Install Updates")); + break; + case UPDATES_NOT_AVAILABLE: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("System Up-To-Date")); + break; + case CHECKING_UPDATES: + gtk_widget_set_sensitive (widget, FALSE); + gtk_button_set_label (GTK_BUTTON (widget), _("Checking for Updates")); + break; + } +} + +static void +on_pk_transaction_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "Package") == 0) + { + self->priv->updates_state = UPDATES_AVAILABLE; + } + else if (g_strcmp0 (signal_name, "Finished") == 0) + { + if (self->priv->updates_state == CHECKING_UPDATES) + self->priv->updates_state = UPDATES_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "ErrorCode") == 0) + { + self->priv->updates_state = PK_NOT_AVAILABLE; + refresh_update_button (self); + } + else if (g_strcmp0 (signal_name, "Destroy") == 0) + { + g_object_unref (self->priv->pk_transaction_proxy); + self->priv->pk_transaction_proxy = NULL; + } +} + +static void +on_pk_get_updates_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + g_warning ("Error getting PackageKit updates list: %s", error->message); + g_error_free (error); + return; + } +} + +static void +on_pk_get_tid_ready (GObject *source, + GAsyncResult *res, + CcInfoPanel *self) +{ + GError *error; + GVariant *result; + char *tid; + + error = NULL; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (result == NULL) + { + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) == FALSE) + g_warning ("Error getting PackageKit transaction ID: %s", error->message); + g_error_free (error); + return; + } + + g_variant_get (result, "(o)", &tid); + + self->priv->pk_transaction_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + tid, + "org.freedesktop.PackageKit.Transaction", + NULL, + NULL); + g_free (tid); + g_variant_unref (result); + + if (self->priv->pk_transaction_proxy == NULL) + { + g_warning ("Unable to get PackageKit transaction proxy object"); + return; + } + + g_signal_connect (self->priv->pk_transaction_proxy, + "g-signal", + G_CALLBACK (on_pk_transaction_signal), + self); + + g_dbus_proxy_call (self->priv->pk_transaction_proxy, + "GetUpdates", + g_variant_new ("(t)", 1), /* PK_FILTER_ENUM_NONE */ + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_updates_ready, + self); +} + +static void +refresh_updates (CcInfoPanel *self) +{ + self->priv->updates_state = CHECKING_UPDATES; + refresh_update_button (self); + + g_assert (self->priv->pk_proxy != NULL); + g_dbus_proxy_call (self->priv->pk_proxy, + "CreateTransaction", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_pk_get_tid_ready, + self); +} + +static void +on_pk_signal (GDBusProxy *proxy, + char *sender_name, + char *signal_name, + GVariant *parameters, + CcInfoPanel *self) +{ + if (g_strcmp0 (signal_name, "UpdatesChanged") == 0) + { + refresh_updates (self); + } +} + +static void +on_updates_button_clicked (GtkWidget *widget, + CcInfoPanel *self) +{ + GError *error; + error = NULL; + g_spawn_command_line_async ("update-manager", &error); + if (error != NULL) + { + g_warning ("unable to launch Software Updates: %s", error->message); + g_error_free (error); + } +} + +static void +cc_info_panel_init (CcInfoPanel *self) +{ + GError *error = NULL; + GtkWidget *widget; + + self->priv = INFO_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + self->priv->session_settings = g_settings_new (GNOME_SESSION_MANAGER_SCHEMA); + self->priv->media_settings = g_settings_new (MEDIA_HANDLING_SCHEMA); + + self->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + g_assert (self->priv->session_bus); + + self->priv->pk_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.PackageKit", + "/org/freedesktop/PackageKit", + "org.freedesktop.PackageKit", + NULL, + NULL); + if (self->priv->pk_proxy == NULL) + { + g_warning ("Unable to get PackageKit proxy object"); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + GVariant *v; + guint32 major, minor, micro; + + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMajor"); + g_variant_get (v, "u", &major); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMinor"); + g_variant_get (v, "u", &minor); + g_variant_unref (v); + v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMicro"); + g_variant_get (v, "u", µ); + g_variant_unref (v); + + if (major != 0 || minor != 8) + { + g_warning ("PackageKit version %u.%u.%u not supported", major, minor, micro); + g_clear_object (&self->priv->pk_proxy); + self->priv->updates_state = PK_NOT_AVAILABLE; + } + else + { + g_signal_connect (self->priv->pk_proxy, + "g-signal", + G_CALLBACK (on_pk_signal), + self); + refresh_updates (self); + } + } + + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/info.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->graphics_data = get_graphics_data (); + + widget = WID ("updates_button"); + g_signal_connect (widget, "clicked", G_CALLBACK (on_updates_button_clicked), self); + + info_panel_setup_selector (self); + info_panel_setup_overview (self); + info_panel_setup_default_apps (self); + info_panel_setup_media (self); + info_panel_setup_graphics (self); +} + +void +cc_info_panel_register (GIOModule *module) +{ + cc_info_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_INFO_PANEL, + "info", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/git_power_gsd_proxies.patch/panels/power/cc-power-panel.c gnome-control-center-3.6.3/.pc/git_power_gsd_proxies.patch/panels/power/cc-power-panel.c --- gnome-control-center-3.6.3/.pc/git_power_gsd_proxies.patch/panels/power/cc-power-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_power_gsd_proxies.patch/panels/power/cc-power-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1162 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2010 Richard Hughes + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include +#include +#include + +#include "cc-power-panel.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +CC_PANEL_REGISTER (CcPowerPanel, cc_power_panel) + +#define POWER_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_POWER_PANEL, CcPowerPanelPrivate)) + +struct _CcPowerPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *power_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + UpClient *up_client; + GtkWidget *levelbar_primary; +}; + +enum +{ + ACTION_MODEL_TEXT, + ACTION_MODEL_VALUE, + ACTION_MODEL_SENSITIVE +}; + +static void +cc_power_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_power_panel_dispose (GObject *object) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (object)->priv; + + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->power_settings) + { + g_object_unref (priv->power_settings); + priv->power_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + if (priv->up_client != NULL) + { + g_object_unref (priv->up_client); + priv->up_client = NULL; + } + + G_OBJECT_CLASS (cc_power_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcPowerPanel *panel) +{ +} + +static const char * +cc_power_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/power"; + else + return "help:gnome-help/power"; +} + +static void +cc_power_panel_class_init (CcPowerPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcPowerPanelPrivate)); + + object_class->get_property = cc_power_panel_get_property; + object_class->set_property = cc_power_panel_set_property; + object_class->dispose = cc_power_panel_dispose; + + panel_class->get_help_uri = cc_power_panel_get_help_uri; +} + +static gchar * +get_timestring (guint64 time_secs) +{ + gchar* timestring = NULL; + gint hours; + gint minutes; + + /* Add 0.5 to do rounding */ + minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); + + if (minutes == 0) + { + timestring = g_strdup (_("Unknown time")); + return timestring; + } + + if (minutes < 60) + { + timestring = g_strdup_printf (ngettext ("%i minute", + "%i minutes", + minutes), minutes); + return timestring; + } + + hours = minutes / 60; + minutes = minutes % 60; + + if (minutes == 0) + { + timestring = g_strdup_printf (ngettext ( + "%i hour", + "%i hours", + hours), hours); + return timestring; + } + + /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" + * Swap order with "%2$s %2$i %1$s %1$i if needed */ + timestring = g_strdup_printf (_("%i %s %i %s"), + hours, ngettext ("hour", "hours", hours), + minutes, ngettext ("minute", "minutes", minutes)); + return timestring; +} + +static void +set_device_battery_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* clear the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_hide (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Charging - %s until fully charged"), + time_string); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low battery, %s remaining"), + time_string); + /* show the warning */ + gtk_widget_show (widget); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using battery power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Using battery power")); + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + details = g_strdup(_("Empty")); + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device until we stumble upon the device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_ups_primary (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + gchar *time_string = NULL; + gdouble percentage; + GtkWidget *widget; + guint64 time; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + &percentage, + &state, + &time); + + /* set the percentage */ + gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->levelbar_primary), + percentage / 100.0f); + + /* always show the warning */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "image_primary_warning")); + gtk_widget_show (widget); + + /* set the description */ + if (time > 0) + { + time_string = get_timestring (time); + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Caution low UPS, %s remaining"), + time_string); + } + else + { + /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */ + details = g_strdup_printf(_("Using UPS power - %s remaining"), + time_string); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + else + { + switch (state) + { + case UP_DEVICE_STATE_DISCHARGING: + if (percentage < 20) + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Caution low UPS")); + } + else + { + /* TRANSLATORS: UPS battery */ + details = g_strdup(_("Using UPS power")); + } + break; + default: + details = g_strdup_printf ("error: %s", + up_device_state_to_string (state)); + break; + } + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_primary")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the primary device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_show (widget); + + /* hide the addon device as extra UPS devices are not possible */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_hide (widget); +out: + g_free (time_string); + g_free (details); +} + +static void +set_device_battery_additional (CcPowerPanel *panel, GVariant *device) +{ + CcPowerPanelPrivate *priv = panel->priv; + gchar *details = NULL; + GtkWidget *widget; + UpDeviceState state; + + /* set the device */ + g_variant_get (device, + "(susdut)", + NULL, /* object_path */ + NULL, /* kind */ + NULL, /* icon_name */ + NULL, /* percentage */ + &state, + NULL /* time */); + + /* set the description */ + switch (state) + { + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: secondary battery is normally in the media bay */ + details = g_strdup(_("Your secondary battery is empty")); + break; + default: + break; + } + if (details == NULL) + goto out; + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "label_battery_addon")); + gtk_label_set_label (GTK_LABEL (widget), details); + + /* show the addon device */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_battery_addon")); + gtk_widget_show (widget); +out: + g_free (details); +} + +static void +add_device_secondary (CcPowerPanel *panel, + GVariant *device, + guint *secondary_devices_cnt) +{ + CcPowerPanelPrivate *priv = panel->priv; + const gchar *icon_name = NULL; + gdouble percentage; + guint64 time; + UpDeviceKind kind; + UpDeviceState state; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *widget; + GString *status; + GString *description; + gboolean show_caution = FALSE; + + g_variant_get (device, + "(susdut)", + NULL, + &kind, + NULL, + &percentage, + &state, + &time); + + switch (kind) + { + case UP_DEVICE_KIND_UPS: + icon_name = "uninterruptible-power-supply"; + show_caution = TRUE; + break; + case UP_DEVICE_KIND_MOUSE: + icon_name = "input-mouse"; + break; + case UP_DEVICE_KIND_KEYBOARD: + icon_name = "input-keyboard"; + break; + case UP_DEVICE_KIND_TABLET: + icon_name = "input-tablet"; + break; + case UP_DEVICE_KIND_PDA: + icon_name = "pda"; + break; + case UP_DEVICE_KIND_PHONE: + icon_name = "phone"; + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + icon_name = "multimedia-player"; + break; + case UP_DEVICE_KIND_COMPUTER: + icon_name = "computer"; + show_caution = TRUE; + break; + default: + icon_name = "battery"; + break; + } + + switch (kind) + { + case UP_DEVICE_KIND_MOUSE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless mouse")); + break; + case UP_DEVICE_KIND_KEYBOARD: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Wireless keyboard")); + break; + case UP_DEVICE_KIND_UPS: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Uninterruptible power supply")); + break; + case UP_DEVICE_KIND_PDA: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Personal digital assistant")); + break; + case UP_DEVICE_KIND_PHONE: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Cellphone")); + break; + case UP_DEVICE_KIND_MEDIA_PLAYER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Media player")); + break; + case UP_DEVICE_KIND_TABLET: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Tablet")); + break; + case UP_DEVICE_KIND_COMPUTER: + /* TRANSLATORS: secondary battery */ + description = g_string_new (_("Computer")); + break; + default: + /* TRANSLATORS: secondary battery, misc */ + description = g_string_new (_("Battery")); + break; + } + g_string_prepend (description, ""); + g_string_append (description, ""); + + switch (state) + { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + /* TRANSLATORS: secondary battery */ + status = g_string_new(C_("Battery power", "Charging")); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + if (percentage < 10 && show_caution) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Caution")); + } + else if (percentage < 30) + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Low")); + } + else + { + /* TRANSLATORS: secondary battery */ + status = g_string_new (C_("Battery power", "Good")); + } + break; + case UP_DEVICE_STATE_FULLY_CHARGED: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Charging - fully charged")); + break; + case UP_DEVICE_STATE_EMPTY: + /* TRANSLATORS: primary battery */ + status = g_string_new(C_("Battery power", "Empty")); + break; + default: + status = g_string_new (up_device_state_to_string (state)); + break; + } + g_string_prepend (status, ""); + g_string_append (status, ""); + + /* create the new widget */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_widget_set_hexpand (hbox, TRUE); + widget = gtk_image_new (); + gtk_misc_set_alignment (GTK_MISC (widget), 0.5f, 0.0f); + gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_DND); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), description->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0f, 0.5f); + gtk_label_set_markup (GTK_LABEL (widget), status->str); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + widget = gtk_level_bar_new (); + gtk_widget_set_margin_right (widget, 32); + gtk_widget_set_margin_top (widget, 3); + gtk_level_bar_set_value (GTK_LEVEL_BAR (widget), percentage / 100.0f); + gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + /* add to the grid */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + + /* two devices wide */ + gtk_grid_attach (GTK_GRID (widget), hbox, + *secondary_devices_cnt % 2, + (*secondary_devices_cnt / 2) - 1, + 1, 1); + (*secondary_devices_cnt)++; + + /* show panel */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_show_all (widget); + + g_string_free (description, TRUE); + g_string_free (status, TRUE); +} + +static void +get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + CcPowerPanel *panel; + CcPowerPanelPrivate *priv; + gboolean got_primary = FALSE; + gboolean ups_as_primary_device = FALSE; + GError *error = NULL; + gsize n_devices; + GList *children; + GList *l; + GtkWidget *widget; + guint i; + guint secondary_devices_cnt = 0; + GVariant *child; + GVariant *result; + GVariant *untuple; + UpDeviceKind kind; + UpDeviceState state; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; /* Must exit before accessing freed memory */ + } + + panel = CC_POWER_PANEL (user_data); + priv = panel->priv; + + /* empty the secondary box */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "grid_secondary")); + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (l = children; l != NULL; l = l->next) + gtk_container_remove (GTK_CONTAINER (widget), l->data); + g_list_free (children); + + /* hide both panels initially */ + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_primary")); + gtk_widget_hide (widget); + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, + "box_secondary")); + gtk_widget_hide (widget); + + if (result == NULL) + { + g_printerr ("Error getting devices: %s\n", error->message); + g_error_free (error); + return; + } + + untuple = g_variant_get_child_value (result, 0); + n_devices = g_variant_n_children (untuple); + + /* first we look for a discharging UPS, which is promoted to the + * primary device if it's discharging. Otherwise we use the first + * listed laptop battery as the primary device */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + &state, + NULL); + if (kind == UP_DEVICE_KIND_UPS && + state == UP_DEVICE_STATE_DISCHARGING) + { + ups_as_primary_device = TRUE; + } + g_variant_unref (child); + } + + /* add the devices now we know the state-of-play */ + for (i = 0; i < n_devices; i++) + { + child = g_variant_get_child_value (untuple, i); + g_variant_get (child, + "(susdut)", + NULL, + &kind, + NULL, + NULL, + NULL, + NULL); + if (kind == UP_DEVICE_KIND_LINE_POWER) + { + /* do nothing */ + } + else if (kind == UP_DEVICE_KIND_UPS && ups_as_primary_device) + { + set_device_ups_primary (panel, child); + } + else if (kind == UP_DEVICE_KIND_BATTERY && !ups_as_primary_device) + { + if (!got_primary) + { + set_device_battery_primary (panel, child); + got_primary = TRUE; + } + else + { + set_device_battery_additional (panel, child); + } + } + else + { + add_device_secondary (panel, child, &secondary_devices_cnt); + } + g_variant_unref (child); + } + + g_variant_unref (untuple); + g_variant_unref (result); +} + +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + CcPowerPanelPrivate *priv = CC_POWER_PANEL (user_data)->priv; + + /* get the new state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GDBusProxy *proxy; + CcPowerPanelPrivate *priv; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* Access user_data after checking for error because user_data might be + disposed already. */ + priv = CC_POWER_PANEL (user_data)->priv; + priv->proxy = proxy; + + /* we want to change the primary device changes */ + g_signal_connect (priv->proxy, + "g-properties-changed", + G_CALLBACK (on_properties_changed), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetDevices", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly expand the dialog */ + priv->cancellable, + get_devices_cb, + user_data); +} + +static void +combo_time_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both keys */ + g_settings_set_int (self->priv->gsd_settings, key, value); +} + +static void +combo_enum_changed_cb (GtkWidget *widget, CcPowerPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + const gchar *key = (const gchar *)g_object_get_data (G_OBJECT(widget), "_gsettings_key"); + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_enum (self->priv->gsd_settings, key, value); +} + +static void +disable_unavailable_combo_items (CcPowerPanel *self, + GtkComboBox *combo_box) +{ + gboolean enabled; + gboolean ret; + gint value_tmp; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkTreeModel *model; + + /* setup the renderer */ + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, + "text", ACTION_MODEL_TEXT, + "sensitive", ACTION_MODEL_SENSITIVE, + NULL); + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* disable any actions we cannot do */ + do + { + gtk_tree_model_get (model, &iter, + ACTION_MODEL_VALUE, &value_tmp, + -1); + switch (value_tmp) { + case GSD_POWER_ACTION_SUSPEND: + enabled = up_client_get_can_suspend (self->priv->up_client); + break; + case GSD_POWER_ACTION_HIBERNATE: + enabled = up_client_get_can_hibernate (self->priv->up_client); + break; + default: + enabled = TRUE; + } + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + ACTION_MODEL_SENSITIVE, enabled, + -1); + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_value_for_combo (GtkComboBox *combo_box, gint value) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value_tmp; + gboolean ret; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + /* try to make the UI match the setting */ + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + break; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +set_ac_battery_ui_mode (CcPowerPanel *self) +{ + gboolean has_batteries = FALSE; + gboolean has_lid = FALSE; + gboolean ret; + GError *error = NULL; + GPtrArray *devices; + guint i; + UpDevice *device; + UpDeviceKind kind; + CcPowerPanelPrivate *priv = self->priv; + + /* this is sync, but it's cached in the daemon and so quick */ + ret = up_client_enumerate_devices_sync (self->priv->up_client, NULL, &error); + if (!ret) + { + g_warning ("failed to get device list: %s", error->message); + g_error_free (error); + goto out; + } + + devices = up_client_get_devices (self->priv->up_client); + for (i=0; ilen; i++) + { + device = g_ptr_array_index (devices, i); + g_object_get (device, + "kind", &kind, + NULL); + if (kind == UP_DEVICE_KIND_BATTERY || + kind == UP_DEVICE_KIND_UPS) + { + has_batteries = TRUE; + break; + } + } + g_ptr_array_unref (devices); + + has_lid = up_client_get_lid_is_present (self->priv->up_client); + +out: + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_ac"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_lid_action"), has_lid); + gtk_widget_set_visible (WID (priv->builder, "combobox_lid_battery"), has_batteries && has_lid); + gtk_widget_set_visible (WID (priv->builder, "label_header_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_header_ac"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_sleep_battery"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "label_critical"), has_batteries); + gtk_widget_set_visible (WID (priv->builder, "combobox_critical"), has_batteries); +} + +static gboolean +activate_link_cb (GtkLabel *label, gchar *uri, CcPowerPanel *self) +{ + CcShell *shell; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (self)); + if (cc_shell_set_active_panel_from_id (shell, uri, NULL, &error) == FALSE) + { + g_warning ("Failed to activate %s panel: %s", uri, error->message); + g_error_free (error); + } + return TRUE; +} + +static void +cc_power_panel_init (CcPowerPanel *self) +{ + GError *error; + GtkWidget *widget; + gint value; + char *text; + + self->priv = POWER_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/power.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + /* add levelbar */ + self->priv->levelbar_primary = GTK_WIDGET + (gtk_builder_get_object (self->priv->builder, "levelbar_primary")); + self->priv->cancellable = g_cancellable_new (); + + /* get initial icon state */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power", + self->priv->cancellable, + got_power_proxy_cb, + self); + + /* find out if there are any battery or UPS devices attached + * and setup UI accordingly */ + self->priv->up_client = up_client_new (); + set_ac_battery_ui_mode (self); + + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + g_signal_connect (self->priv->gsd_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + + /* auto-sleep time */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-ac-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_ac")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-ac-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + value = g_settings_get_int (self->priv->gsd_settings, "sleep-inactive-battery-timeout"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_sleep_battery")); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "sleep-inactive-battery-timeout"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_time_changed_cb), + self); + + /* actions */ + value = g_settings_get_enum (self->priv->gsd_settings, "critical-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_critical")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "critical-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + /* set screen link */ + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "label_screen_settings")); + /* TRANSLATORS: this is a link to the "Brightness and Lock" control center panel */ + text = g_strdup_printf ("%s", + _("Tip: screen brightness affects how much power is used")); + gtk_label_set_markup (GTK_LABEL (widget), text); + g_free (text); + + g_signal_connect (widget, "activate-link", + G_CALLBACK (activate_link_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-ac-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_ac")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-ac-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + value = g_settings_get_enum (self->priv->gsd_settings, "lid-close-battery-action"); + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_lid_battery")); + disable_unavailable_combo_items (self, GTK_COMBO_BOX (widget)); + set_value_for_combo (GTK_COMBO_BOX (widget), value); + g_object_set_data (G_OBJECT(widget), "_gsettings_key", "lid-close-battery-action"); + g_signal_connect (widget, "changed", + G_CALLBACK (combo_enum_changed_cb), + self); + + widget = WID (self->priv->builder, "vbox_power"); + gtk_widget_reparent (widget, (GtkWidget *) self); + + /* Set up Unity-specific controls */ + /* References: + * https://wiki.ubuntu.com/Power + * https://docs.google.com/document/d/1ILTJDiDCd25Npt2AmgzF8aOnZZECxTfM0hvsbWT2BxA/edit?pli=1#heading=h.i5lg1g344bsb + */ + // First check the schema is installed + GSettingsSchemaSource *schema_source = g_settings_schema_source_ref ( + g_settings_schema_source_get_default ()); + GSettingsSchema *schema = g_settings_schema_source_lookup ( + schema_source, + "com.canonical.indicator.power", + TRUE); + g_settings_schema_source_unref (schema_source); + + if (schema) + { + widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, + "combobox_indicator")); + self->priv->power_settings = g_settings_new ("com.canonical.indicator.power"); + g_settings_bind (self->priv->power_settings, "icon-policy", + widget, "active-id", G_SETTINGS_BIND_DEFAULT); + g_settings_schema_unref (schema); + } + else + { + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "separator_indicator"))); + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "label_indicator"))); + gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "combobox_indicator"))); + } + +} + +void +cc_power_panel_register (GIOModule *module) +{ + cc_power_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_POWER_PANEL, + "power", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/configure.ac gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/configure.ac --- gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,551 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0 x11) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +shell/libgnome-control-center.pc +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/gnome-bluetooth-panel.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/panels/region/gnome-region-panel-input.c gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/panels/region/gnome-region-panel-input.c --- gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/panels/region/gnome-region-panel-input.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_region_update_input_switch.patch/panels/region/gnome-region-panel-input.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1580 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by: Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#include +#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#ifdef HAVE_IBUS +#include +#endif + +#include "gdm-languages.h" +#include "gnome-region-panel-input.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s)) + +#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" + +#define KEY_CURRENT_INPUT_SOURCE "current" +#define KEY_INPUT_SOURCES "sources" + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +enum { + NAME_COLUMN, + TYPE_COLUMN, + ID_COLUMN, + SETUP_COLUMN, + N_COLUMNS +}; + +static GSettings *input_sources_settings = NULL; +static GnomeXkbInfo *xkb_info = NULL; +static GtkWidget *input_chooser = NULL; /* weak pointer */ + +#ifdef HAVE_IBUS +static IBusBus *ibus = NULL; +static GHashTable *ibus_engines = NULL; +static GCancellable *ibus_cancellable = NULL; +static guint shell_name_watch_id = 0; + +static const gchar *supported_ibus_engines[] = { + /* Simplified Chinese */ + "pinyin", + "bopomofo", + "wubi", + "erbi", + /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ + "libpinyin", + "libbopomofo", + + /* Traditional Chinese */ + /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ + "chewing", + "cangjie5", + "cangjie3", + "quick5", + "quick3", + "stroke5", + + /* Japanese */ + "anthy", + "mozc-jp", + "skk", + + /* Korean */ + "hangul", + + /* Thai */ + "m17n:th:kesmanee", + "m17n:th:pattachote", + "m17n:th:tis820", + + /* Vietnamese */ + "m17n:vi:tcvn", + "m17n:vi:telex", + "m17n:vi:viqr", + "m17n:vi:vni", + "Unikey", + + /* Sinhala */ + "m17n:si:wijesekera", + "m17n:si:phonetic-dynamic", + "m17n:si:trans", + "sayura", + + /* Indic */ + /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ + + /* Assamese */ + "m17n:as:phonetic", + "m17n:as:inscript", + "m17n:as:itrans", + + /* Bengali */ + "m17n:bn:inscript", + "m17n:bn:itrans", + "m17n:bn:probhat", + + /* Gujarati */ + "m17n:gu:inscript", + "m17n:gu:itrans", + "m17n:gu:phonetic", + + /* Hindi */ + "m17n:hi:inscript", + "m17n:hi:itrans", + "m17n:hi:phonetic", + "m17n:hi:remington", + "m17n:hi:typewriter", + "m17n:hi:vedmata", + + /* Kannada */ + "m17n:kn:kgp", + "m17n:kn:inscript", + "m17n:kn:itrans", + + /* Kashmiri */ + "m17n:ks:inscript", + + /* Maithili */ + "m17n:mai:inscript", + + /* Malayalam */ + "m17n:ml:inscript", + "m17n:ml:itrans", + "m17n:ml:mozhi", + "m17n:ml:swanalekha", + + /* Marathi */ + "m17n:mr:inscript", + "m17n:mr:itrans", + "m17n:mr:phonetic", + + /* Nepali */ + "m17n:ne:rom", + "m17n:ne:trad", + + /* Oriya */ + "m17n:or:inscript", + "m17n:or:itrans", + "m17n:or:phonetic", + + /* Punjabi */ + "m17n:pa:inscript", + "m17n:pa:itrans", + "m17n:pa:phonetic", + "m17n:pa:jhelum", + + /* Sanskrit */ + "m17n:sa:harvard-kyoto", + + /* Sindhi */ + "m17n:sd:inscript", + + /* Tamil */ + "m17n:ta:tamil99", + "m17n:ta:inscript", + "m17n:ta:itrans", + "m17n:ta:phonetic", + "m17n:ta:lk-renganathan", + "m17n:ta:vutam", + "m17n:ta:typewriter", + + /* Telugu */ + "m17n:te:inscript", + "m17n:te:apple", + "m17n:te:pothana", + "m17n:te:rts", + + /* Urdu */ + "m17n:ur:phonetic", + + /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ + "m17n:as:inscript2", + "m17n:bn:inscript2", + "m17n:brx:inscript2-deva", + "m17n:doi:inscript2-deva", + "m17n:gu:inscript2", + "m17n:hi:inscript2", + "m17n:kn:inscript2", + "m17n:kok:inscript2-deva", + "m17n:mai:inscript2", + "m17n:ml:inscript2", + "m17n:mni:inscript2-beng", + "m17n:mni:inscript2-mtei", + "m17n:mr:inscript2", + "m17n:ne:inscript2-deva", + "m17n:or:inscript2", + "m17n:pa:inscript2-guru", + "m17n:sa:inscript2", + "m17n:sat:inscript2-deva", + "m17n:sat:inscript2-olck", + "m17n:sd:inscript2-deva", + "m17n:ta:inscript2", + "m17n:te:inscript2", + + /* No corresponding XKB map available for the languages */ + + /* Chinese Yi */ + "m17n:ii:phonetic", + + /* Tai-Viet */ + "m17n:tai:sonla", + + /* Kazakh in Arabic script */ + "m17n:kk:arabic", + + /* Yiddish */ + "m17n:yi:yivo", + + /* Canadian Aboriginal languages */ + "m17n:ath:phonetic", + "m17n:bla:phonetic", + "m17n:cr:western", + "m17n:iu:phonetic", + "m17n:nsk:phonetic", + "m17n:oj:phonetic", + + /* Non-trivial engines, like transliteration-based instead of + keymap-based. Confirmation needed that the engines below are + actually used by local language users. */ + + /* Tibetan */ + "m17n:bo:ewts", + "m17n:bo:tcrc", + "m17n:bo:wylie", + + /* Esperanto */ + "m17n:eo:h-f", + "m17n:eo:h", + "m17n:eo:plena", + "m17n:eo:q", + "m17n:eo:vi", + "m17n:eo:x", + + /* Amharic */ + "m17n:am:sera", + + /* Russian */ + "m17n:ru:translit", + + /* Classical Greek */ + "m17n:grc:mizuochi", + + /* Lao */ + "m17n:lo:lrt", + + /* Postfix modifier input methods */ + "m17n:da:post", + "m17n:sv:post", + NULL +}; +#endif /* HAVE_IBUS */ + +static void populate_model (GtkListStore *store, + GtkListStore *active_sources_store); +static GtkWidget *input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources); +static gboolean input_chooser_get_selected (GtkWidget *chooser, + GtkTreeModel **model, + GtkTreeIter *iter); +static GtkTreeModel *tree_view_get_actual_model (GtkTreeView *tv); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +#ifdef HAVE_IBUS +static void +clear_ibus (void) +{ + if (shell_name_watch_id > 0) + { + g_bus_unwatch_name (shell_name_watch_id); + shell_name_watch_id = 0; + } + g_cancellable_cancel (ibus_cancellable); + g_clear_object (&ibus_cancellable); + g_clear_pointer (&ibus_engines, g_hash_table_destroy); + g_clear_object (&ibus); +} + +static gchar * +engine_get_display_name (IBusEngineDesc *engine_desc) +{ + const gchar *name; + const gchar *language_code; + const gchar *language; + gchar *display_name; + + name = ibus_engine_desc_get_longname (engine_desc); + language_code = ibus_engine_desc_get_language (engine_desc); + language = ibus_get_language_name (language_code); + + display_name = g_strdup_printf ("%s (%s)", language, name); + + return display_name; +} + +static GDesktopAppInfo * +setup_app_info_for_id (const gchar *id) +{ + GDesktopAppInfo *app_info; + gchar *desktop_file_name; + gchar **strv; + + strv = g_strsplit (id, ":", 2); + desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]); + g_strfreev (strv); + + app_info = g_desktop_app_info_new (desktop_file_name); + g_free (desktop_file_name); + + return app_info; +} + +static void +input_chooser_repopulate (GtkListStore *active_sources_store) +{ + GtkBuilder *builder; + GtkListStore *model; + + if (!input_chooser) + return; + + builder = g_object_get_data (G_OBJECT (input_chooser), "builder"); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + gtk_list_store_clear (model); + populate_model (model, active_sources_store); +} + +static void +update_ibus_active_sources (GtkBuilder *builder) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type, *id; + gboolean ret; + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + model = tree_view_get_actual_model (tv); + + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { + IBusEngineDesc *engine_desc = NULL; + GDesktopAppInfo *app_info = NULL; + gchar *display_name = NULL; + + engine_desc = g_hash_table_lookup (ibus_engines, id); + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + NAME_COLUMN, display_name, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + } + + g_free (type); + g_free (id); + + ret = gtk_tree_model_iter_next (model, &iter); + } + + input_chooser_repopulate (GTK_LIST_STORE (model)); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + GtkBuilder *builder) +{ + gboolean show_all_sources; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (ibus, result, &error); + + g_clear_object (&ibus_cancellable); + + if (!list && error) + { + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + show_all_sources = g_settings_get_boolean (input_sources_settings, "show-all-sources"); + + /* Maps engine ids to engine description objects */ + ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) + { + IBusEngineDesc *engine = l->data; + const gchar *engine_id = ibus_engine_desc_get_name (engine); + + if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); + else + g_object_unref (engine); + } + g_list_free (list); + + update_ibus_active_sources (builder); +} + +static void +fetch_ibus_engines (GtkBuilder *builder) +{ + ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (ibus, + -1, + ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + builder); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (ibus, fetch_ibus_engines, builder); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} + +static void +on_shell_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer data) +{ + GtkBuilder *builder = data; + + if (!ibus) + { + ibus = ibus_bus_new_async (); + if (ibus_bus_is_connected (ibus)) + fetch_ibus_engines (builder); + else + g_signal_connect_swapped (ibus, "connected", + G_CALLBACK (fetch_ibus_engines), builder); + } + maybe_start_ibus (); +} +#endif /* HAVE_IBUS */ + +static gboolean +add_source_to_table (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GHashTable *hash = data; + gchar *type; + gchar *id; + + gtk_tree_model_get (model, iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + g_hash_table_add (hash, g_strconcat (type, id, NULL)); + + g_free (type); + g_free (id); + + return FALSE; +} + +static void +populate_model (GtkListStore *store, + GtkListStore *active_sources_store) +{ + GHashTable *active_sources_table; + GtkTreeIter iter; + const gchar *name; + GList *sources, *tmp; + gchar *source_id = NULL; + + active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources_store), + add_source_to_table, + active_sources_table); + + sources = gnome_xkb_info_get_all_layouts (xkb_info); + + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_XKB, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data, + &name, NULL, NULL, NULL); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB, + ID_COLUMN, tmp->data, + -1); + } + g_free (source_id); + + g_list_free (sources); + +#ifdef HAVE_IBUS + if (ibus_engines) + { + gchar *display_name; + + sources = g_hash_table_get_keys (ibus_engines); + + source_id = NULL; + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_IBUS, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS, + ID_COLUMN, tmp->data, + -1); + g_free (display_name); + } + g_free (source_id); + + g_list_free (sources); + } +#endif + + g_hash_table_destroy (active_sources_table); +} + +static void +populate_with_active_sources (GtkListStore *store) +{ + GVariant *sources; + GVariantIter iter; + const gchar *name; + const gchar *type; + const gchar *id; + gchar *display_name; + GDesktopAppInfo *app_info; + GtkTreeIter tree_iter; + + sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) + { + display_name = NULL; + app_info = NULL; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (!name) + { + g_warning ("Couldn't find XKB input source '%s'", id); + continue; + } + display_name = g_strdup (name); + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + continue; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + continue; + } + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set (store, &tree_iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + + g_variant_unref (sources); +} + +static void +update_configuration (GtkTreeModel *model) +{ + GtkTreeIter iter; + gchar *type; + gchar *id; + GVariantBuilder builder; + GVariant *old_sources; + const gchar *old_current_type; + const gchar *old_current_id; + guint old_current_index; + guint old_n_sources; + guint index; + + old_sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + old_current_index = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE); + old_n_sources = g_variant_n_children (old_sources); + + if (old_n_sources > 0 && old_current_index < old_n_sources) + { + g_variant_get_child (old_sources, + old_current_index, + "(&s&s)", + &old_current_type, + &old_current_id); + } + else + { + old_current_type = ""; + old_current_id = ""; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); + index = 0; + gtk_tree_model_get_iter_first (model, &iter); + do + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + if (index != old_current_index && + g_str_equal (type, old_current_type) && + g_str_equal (id, old_current_id)) + { + g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, index); + } + g_variant_builder_add (&builder, "(ss)", type, id); + g_free (type); + g_free (id); + index += 1; + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); + g_settings_apply (input_sources_settings); + + g_variant_unref (old_sources); +} + +static gboolean +get_selected_iter (GtkBuilder *builder, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + return gtk_tree_selection_get_selected (selection, model, iter); +} + +static gint +idx_from_model_iter (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gint idx; + + path = gtk_tree_model_get_path (model, iter); + if (path == NULL) + return -1; + + idx = gtk_tree_path_get_indices (path)[0]; + gtk_tree_path_free (path); + + return idx; +} + +static void +update_button_sensitivity (GtkBuilder *builder) +{ + GtkWidget *remove_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *show_button; + GtkWidget *settings_button; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gint n_active; + gint index; + gboolean settings_sensitive; + GDesktopAppInfo *app_info; + + remove_button = WID("input_source_remove"); + show_button = WID("input_source_show"); + up_button = WID("input_source_move_up"); + down_button = WID("input_source_move_down"); + settings_button = WID("input_source_settings"); + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL); + + if (get_selected_iter (builder, &model, &iter)) + { + index = idx_from_model_iter (model, &iter); + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + } + else + { + index = -1; + app_info = NULL; + } + + settings_sensitive = (index >= 0 && app_info != NULL); + + if (app_info) + g_object_unref (app_info); + + gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1); + gtk_widget_set_sensitive (show_button, index >= 0); + gtk_widget_set_sensitive (up_button, index > 0); + gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); + gtk_widget_set_sensitive (settings_button, settings_sensitive); +} + +static void +set_selected_path (GtkBuilder *builder, + GtkTreePath *path) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + gtk_tree_selection_select_path (selection, path); +} + +static GtkTreeModel * +tree_view_get_actual_model (GtkTreeView *tv) +{ + GtkTreeModel *filtered_store; + + filtered_store = gtk_tree_view_get_model (tv); + + return gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered_store)); +} + +static void +chooser_response (GtkWidget *chooser, gint response_id, gpointer data) +{ + GtkBuilder *builder = data; + + if (response_id == GTK_RESPONSE_OK) + { + GtkTreeModel *model; + GtkTreeIter iter; + + if (input_chooser_get_selected (chooser, &model, &iter)) + { + GtkTreeView *tv; + GtkListStore *child_model; + GtkTreeIter child_iter, filter_iter; + gchar *name; + gchar *type; + gchar *id; + GDesktopAppInfo *app_info = NULL; + + gtk_tree_model_get (model, &iter, + NAME_COLUMN, &name, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + +#ifdef HAVE_IBUS + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + app_info = setup_app_info_for_id (id); +#endif + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + child_model = GTK_LIST_STORE (tree_view_get_actual_model (tv)); + + gtk_list_store_append (child_model, &child_iter); + + gtk_list_store_set (child_model, &child_iter, + NAME_COLUMN, name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (name); + g_free (type); + g_free (id); + if (app_info) + g_object_unref (app_info); + + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tv)), + &filter_iter, + &child_iter); + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tv), &filter_iter); + + update_button_sensitivity (builder); + update_configuration (GTK_TREE_MODEL (child_model)); + } + else + { + g_debug ("nothing selected, nothing added"); + } + } + + gtk_widget_destroy (GTK_WIDGET (chooser)); +} + +static void +add_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkWidget *chooser; + GtkWidget *toplevel; + GtkWidget *treeview; + GtkListStore *active_sources; + + g_debug ("add an input source"); + + toplevel = gtk_widget_get_toplevel (WID ("region_notebook")); + treeview = WID ("active_input_sources"); + active_sources = GTK_LIST_STORE (tree_view_get_actual_model (GTK_TREE_VIEW (treeview))); + + chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources); + g_signal_connect (chooser, "response", + G_CALLBACK (chooser_response), builder); +} + +static void +remove_selected_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter child_iter; + GtkTreePath *path; + + g_debug ("remove selected input source"); + + if (get_selected_iter (builder, &model, &iter) == FALSE) + return; + + path = gtk_tree_model_get_path (model, &iter); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_list_store_remove (GTK_LIST_STORE (child_model), &child_iter); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + gtk_tree_path_prev (path); + + set_selected_path (builder, path); + + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_up (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, prev; + GtkTreeIter child_iter, child_prev; + GtkTreePath *path; + + g_debug ("move selected input source up"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + prev = iter; + if (!gtk_tree_model_iter_previous (model, &prev)) + return; + + path = gtk_tree_model_get_path (model, &prev); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_prev, + &prev); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_prev); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_down (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, next; + GtkTreeIter child_iter, child_next; + GtkTreePath *path; + + g_debug ("move selected input source down"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + next = iter; + if (!gtk_tree_model_iter_next (model, &next)) + return; + + path = gtk_tree_model_get_path (model, &next); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_next, + &next); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_next); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +show_selected_layout (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *id; + gchar *kbd_viewer_args; + const gchar *xkb_layout; + const gchar *xkb_variant; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, NULL, NULL, &xkb_layout, &xkb_variant); + + if (!xkb_layout || !xkb_layout[0]) + { + g_warning ("Couldn't find XKB input source '%s'", id); + goto exit; + } + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + xkb_layout = ibus_engine_desc_get_layout (engine_desc); + xkb_variant = ""; + } + else + { + g_warning ("Couldn't find IBus input source '%s'", id); + goto exit; + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + goto exit; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + goto exit; + } + + if (xkb_variant[0]) + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", + xkb_layout, xkb_variant); + else + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", + xkb_layout); + + g_spawn_command_line_async (kbd_viewer_args, NULL); + + g_free (kbd_viewer_args); + exit: + g_free (type); + g_free (id); +} + +static void +show_selected_settings (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + GdkAppLaunchContext *ctx; + GDesktopAppInfo *app_info; + gchar *id; + GError *error = NULL; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + + if (!app_info) + return; + + ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); + gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ()); + + gtk_tree_model_get (model, &iter, ID_COLUMN, &id, -1); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx), + "IBUS_ENGINE_NAME", + id); + g_free (id); + + if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) + { + g_warning ("Failed to launch input source setup: %s", error->message); + g_error_free (error); + } + + g_object_unref (ctx); + g_object_unref (app_info); +} + +static gboolean +go_to_shortcuts (GtkLinkButton *button, + CcRegionPanel *panel) +{ + CcShell *shell; + const gchar *argv[] = { "shortcuts", "Typing", NULL }; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error)) + { + g_warning ("Failed to activate Keyboard panel: %s", error->message); + g_error_free (error); + } + + return TRUE; +} + +static void +input_sources_changed (GSettings *settings, + gchar *key, + GtkBuilder *builder) +{ + GtkWidget *treeview; + GtkTreeModel *store; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeModel *model; + + treeview = WID("active_input_sources"); + store = tree_view_get_actual_model (GTK_TREE_VIEW (treeview)); + + if (get_selected_iter (builder, &model, &iter)) + path = gtk_tree_model_get_path (model, &iter); + else + path = NULL; + + gtk_list_store_clear (GTK_LIST_STORE (store)); + populate_with_active_sources (GTK_LIST_STORE (store)); + + if (path) + { + set_selected_path (builder, path); + gtk_tree_path_free (path); + } +} + +static void +update_shortcut_label (GtkWidget *widget, + const char *value) +{ + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + if (value == NULL || *value == '\0') + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +update_shortcuts (GtkBuilder *builder) +{ + char *previous, *next; + GSettings *settings; + + settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + + previous = g_settings_get_string (settings, "switch-input-source-backward"); + next = g_settings_get_string (settings, "switch-input-source"); + + update_shortcut_label (WID ("prev-source-shortcut-label"), previous); + update_shortcut_label (WID ("next-source-shortcut-label"), next); + + g_free (previous); + g_free (next); +} + +static gboolean +active_sources_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *display_name; + + gtk_tree_model_get (model, iter, NAME_COLUMN, &display_name, -1); + + if (!display_name) + return FALSE; + + g_free (display_name); + + return TRUE; +} + +void +setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *panel) +{ + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkListStore *store; + GtkTreeModel *filtered_store; + GtkTreeSelection *selection; + + /* set up the list of active inputs */ + treeview = WID("active_input_sources"); + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_DESKTOP_APP_INFO); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); + g_settings_delay (input_sources_settings); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) g_object_unref, input_sources_settings); + + if (!xkb_info) + xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + builder, + NULL); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) clear_ibus, NULL); +#endif + + populate_with_active_sources (store); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect_swapped (selection, "changed", + G_CALLBACK (update_button_sensitivity), builder); + + /* Some input source types might have their info loaded + * asynchronously. In that case we don't want to show them + * immediately so we use a filter model on top of the real model + * which mirrors the GSettings key. */ + filtered_store = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered_store), + active_sources_visible_func, + NULL, + NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), filtered_store); + + /* set up the buttons */ + g_signal_connect (WID("input_source_add"), "clicked", + G_CALLBACK (add_input), builder); + g_signal_connect (WID("input_source_remove"), "clicked", + G_CALLBACK (remove_selected_input), builder); + g_signal_connect (WID("input_source_move_up"), "clicked", + G_CALLBACK (move_selected_input_up), builder); + g_signal_connect (WID("input_source_move_down"), "clicked", + G_CALLBACK (move_selected_input_down), builder); + g_signal_connect (WID("input_source_show"), "clicked", + G_CALLBACK (show_selected_layout), builder); + g_signal_connect (WID("input_source_settings"), "clicked", + G_CALLBACK (show_selected_settings), builder); + + /* use an em dash is no shortcut */ + update_shortcuts (builder); + + g_signal_connect (WID("jump-to-shortcuts"), "activate-link", + G_CALLBACK (go_to_shortcuts), panel); + + g_signal_connect (G_OBJECT (input_sources_settings), + "changed::" KEY_INPUT_SOURCES, + G_CALLBACK (input_sources_changed), + builder); + + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-true"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (input_sources_settings, "per-window", + WID("per-window-radio-false"), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + /* because we are in delay-apply mode */ + g_signal_connect_swapped (WID("per-window-radio-true"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); + g_signal_connect_swapped (WID("per-window-radio-false"), "clicked", + G_CALLBACK (g_settings_apply), input_sources_settings); +} + +static void +filter_clear (GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + gpointer user_data) +{ + gtk_entry_set_text (entry, ""); +} + +static gchar **search_pattern_list; + +static void +filter_changed (GtkBuilder *builder) +{ + GtkTreeModelFilter *filtered_model; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreeIter selected_iter; + GtkWidget *filter_entry; + const gchar *pattern; + gchar *upattern; + + filter_entry = WID ("input_source_filter"); + pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry)); + upattern = g_utf8_strup (pattern, -1); + if (!g_strcmp0 (pattern, "")) + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-find-symbolic", + "secondary-icon-activatable", FALSE, + "secondary-icon-sensitive", FALSE, + NULL); + else + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-clear-symbolic", + "secondary-icon-activatable", TRUE, + "secondary-icon-sensitive", TRUE, + NULL); + + if (search_pattern_list != NULL) + g_strfreev (search_pattern_list); + + search_pattern_list = g_strsplit (upattern, " ", -1); + g_free (upattern); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + gtk_tree_model_filter_refilter (filtered_model); + + tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list")); + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model), + &selected_iter); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free (path); + } + else + { + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkBuilder *builder) +{ + gtk_widget_set_sensitive (WID ("ok-button"), + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkBuilder *builder) +{ + GtkWidget *add_button; + GtkWidget *dialog; + + add_button = WID ("ok-button"); + dialog = WID ("input_source_chooser"); + if (gtk_widget_is_sensitive (add_button)) + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +entry_activated (GtkBuilder *builder, + gpointer data) +{ + row_activated (NULL, NULL, NULL, builder); +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name = NULL; + gchar **pattern; + gboolean rv = TRUE; + + if (search_pattern_list == NULL || search_pattern_list[0] == NULL) + return TRUE; + + gtk_tree_model_get (model, iter, + NAME_COLUMN, &name, + -1); + + pattern = search_pattern_list; + do { + gboolean is_pattern_found = FALSE; + gchar *udesc = g_utf8_strup (name, -1); + if (udesc != NULL && g_strstr_len (udesc, -1, *pattern)) + { + is_pattern_found = TRUE; + } + g_free (udesc); + + if (!is_pattern_found) + { + rv = FALSE; + break; + } + + } while (*++pattern != NULL); + + g_free (name); + + return rv; +} + +static GtkWidget * +input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources) +{ + GtkBuilder *builder; + GtkWidget *chooser; + GtkWidget *filtered_list; + GtkWidget *filter_entry; + GtkTreeViewColumn *visible_column; + GtkTreeSelection *selection; + GtkListStore *model; + GtkTreeModelFilter *filtered_model; + GtkTreeIter iter; + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, + GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui", + NULL); + chooser = WID ("input_source_chooser"); + input_chooser = chooser; + g_object_add_weak_pointer (G_OBJECT (chooser), (gpointer *) &input_chooser); + g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref); + + filtered_list = WID ("filtered_input_source_list"); + filter_entry = WID ("input_source_filter"); + + g_object_set_data (G_OBJECT (chooser), + "filtered_input_source_list", filtered_list); + visible_column = + gtk_tree_view_column_new_with_attributes ("Input Sources", + gtk_cell_renderer_text_new (), + "text", NAME_COLUMN, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window); + + gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list), + visible_column); + /* We handle searching ourselves, thank you. */ + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1); + + g_signal_connect_swapped (G_OBJECT (filter_entry), "activate", + G_CALLBACK (entry_activated), builder); + g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text", + G_CALLBACK (filter_changed), builder); + + g_signal_connect (G_OBJECT (filter_entry), "icon-release", + G_CALLBACK (filter_clear), NULL); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + populate_model (model, active_sources); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + NAME_COLUMN, GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (filtered_model, + filter_func, + NULL, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list)); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), builder); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + + g_signal_connect (G_OBJECT (filtered_list), "row-activated", + G_CALLBACK (row_activated), builder); + + gtk_widget_grab_focus (filter_entry); + + gtk_widget_show (chooser); + + return chooser; +} + +static gboolean +input_chooser_get_selected (GtkWidget *dialog, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkWidget *tv; + GtkTreeSelection *selection; + + tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list"); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + + return gtk_tree_selection_get_selected (selection, model, iter); +} diff -Nru gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/configure.ac gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/configure.ac --- gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,551 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0 x11) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +shell/libgnome-control-center.pc +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/bluetooth-properties.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/bluetooth-properties.desktop.in.in gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/bluetooth-properties.desktop.in.in --- gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/bluetooth-properties.desktop.in.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/bluetooth-properties.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,15 @@ +[Desktop Entry] +_Name=Bluetooth +_Comment=Configure Bluetooth settings +Icon=bluetooth +Exec=gnome-control-center bluetooth +Terminal=false +Type=Application +Categories=GTK;GNOME;Settings;X-GNOME-NetworkSettings;HardwareSettings;X-GNOME-Settings-Panel; +OnlyShowIn=GNOME;Unity; +StartupNotify=true +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-bluetooth +X-GNOME-Bugzilla-Component=properties +X-GNOME-Bugzilla-Version=@VERSION@ +X-GNOME-Settings-Panel=bluetooth diff -Nru gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/Makefile.am gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/Makefile.am --- gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/panels/bluetooth/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,33 @@ +# This is used in PANEL_CFLAGS +cappletname = bluetooth + +ccpanelsdir = $(PANELS_DIR) +ccpanels_LTLIBRARIES = libbluetooth.la + +INCLUDES = \ + $(PANEL_CFLAGS) \ + $(BLUETOOTH_CFLAGS) \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + -DPKGDATADIR="\"$(pkgdatadir)\"" \ + $(NULL) + +libbluetooth_la_SOURCES = \ + cc-bluetooth-panel.c \ + cc-bluetooth-panel.h + +libbluetooth_la_LIBADD = $(PANEL_LIBS) $(BLUETOOTH_LIBS) +libbluetooth_la_LDFLAGS = $(PANEL_LDFLAGS) + +desktopdir = $(datadir)/applications +desktop_in_in_files = bluetooth-properties.desktop.in.in +desktop_in_files = bluetooth-properties.desktop.in +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) +@INTLTOOL_DESKTOP_RULE@ + +ui_DATA = bluetooth.ui +uidir = $(pkgdatadir) + +CLEANFILES = $(desktop_DATA) +EXTRA_DIST = $(man_MANS) $(desktop_in_in_files) $(ui_DATA) + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.in gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.in --- gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,137 @@ +# Add files with translateable strings here. +# Please keep this file sorted alphabetically. +[encoding: UTF-8] +[type: gettext/glade]panels/background/background.ui +panels/background/bg-colors-source.c +panels/background/cc-background-chooser-dialog.c +panels/background/cc-background-item.c +panels/background/cc-background-panel.c +panels/background/gnome-background-panel.desktop.in.in +panels/bluetooth/bluetooth-properties.desktop.in.in +[type: gettext/glade]panels/bluetooth/bluetooth.ui +panels/bluetooth/cc-bluetooth-panel.c +panels/color/cc-color-panel.c +[type: gettext/glade]panels/color/color.ui +panels/color/gnome-color-panel.desktop.in.in +panels/common/cc-common-language.c +panels/common/cc-language-chooser.c +panels/common/gdm-languages.c +[type: gettext/glade]panels/common/language-chooser.ui +[type: gettext/glade]panels/datetime/datetime.ui +panels/datetime/gnome-datetime-panel.desktop.in.in +panels/datetime/org.gnome.controlcenter.datetime.policy.in +panels/display/cc-display-panel.c +[type: gettext/glade]panels/display/display-capplet.ui +panels/display/gnome-display-panel.desktop.in.in +panels/info/cc-info-panel.c +panels/info/gnome-info-panel.desktop.in.in +[type: gettext/glade]panels/info/info.ui +panels/keyboard/00-multimedia.xml.in +panels/keyboard/01-input-sources.xml.in +panels/keyboard/01-launchers.xml.in +panels/keyboard/01-screenshot.xml.in +panels/keyboard/01-system.xml.in +panels/keyboard/50-accessibility.xml.in +panels/keyboard/cc-keyboard-option.c +panels/keyboard/gnome-keyboard-panel.desktop.in.in +[type: gettext/glade]panels/keyboard/gnome-keyboard-panel.ui +panels/keyboard/keyboard-shortcuts.c +panels/mouse/cc-mouse-panel.c +panels/mouse/gnome-mouse-panel.desktop.in.in +panels/mouse/gnome-mouse-properties.c +[type: gettext/glade]panels/mouse/gnome-mouse-properties.ui +panels/mouse/gnome-mouse-test.c +[type: gettext/glade]panels/mouse/gnome-mouse-test.ui +panels/network/cc-network-panel.c +panels/network/gnome-network-panel.desktop.in.in +panels/network/net-device-mobile.c +panels/network/net-device-wifi.c +panels/network/net-device-wired.c +panels/network/net-proxy.c +panels/network/net-vpn.c +[type: gettext/glade]panels/network/network-mobile.ui +[type: gettext/glade]panels/network/network-proxy.ui +[type: gettext/glade]panels/network/network.ui +[type: gettext/glade]panels/network/network-vpn.ui +[type: gettext/glade]panels/network/network-wifi.ui +[type: gettext/glade]panels/network/network-wired.ui +panels/network/panel-common.c +panels/online-accounts/cc-online-accounts-add-account-dialog.c +panels/online-accounts/cc-online-accounts-panel.c +panels/online-accounts/gnome-online-accounts-panel.desktop.in.in +[type: gettext/glade]panels/online-accounts/online-accounts.ui +panels/power/cc-power-panel.c +panels/power/gnome-power-panel.desktop.in.in +[type: gettext/glade]panels/power/power.ui +panels/printers/cc-printers-panel.c +panels/printers/gnome-printers-panel.desktop.in.in +[type: gettext/glade]panels/printers/jobs-dialog.ui +[type: gettext/glade]panels/printers/new-printer-dialog.ui +[type: gettext/glade]panels/printers/options-dialog.ui +[type: gettext/glade]panels/printers/ppd-selection-dialog.ui +panels/printers/pp-ipp-option-widget.c +panels/printers/pp-jobs-dialog.c +panels/printers/pp-new-printer-dialog.c +panels/printers/pp-options-dialog.c +panels/printers/pp-ppd-option-widget.c +panels/printers/pp-ppd-selection-dialog.c +[type: gettext/glade]panels/printers/printers.ui +panels/region/gnome-region-panel.desktop.in.in +panels/region/gnome-region-panel-formats.c +[type: gettext/glade]panels/region/gnome-region-panel-input-chooser.ui +panels/region/gnome-region-panel-system.c +[type: gettext/glade]panels/region/gnome-region-panel.ui +panels/screen/gnome-screen-panel.desktop.in.in +[type: gettext/glade]panels/screen/screen.ui +panels/sound/applet-main.c +panels/sound/cc-sound-panel.c +panels/sound/data/gnome-sound-applet.desktop.in +panels/sound/data/gnome-sound-panel.desktop.in.in +panels/sound/data/sounds/gnome-sounds-default.xml.in.in +panels/sound/gvc-applet.c +panels/sound/gvc-balance-bar.c +panels/sound/gvc-channel-bar.c +panels/sound/gvc-combo-box.c +panels/sound/gvc-mixer-control.c +panels/sound/gvc-mixer-dialog.c +panels/sound/gvc-sound-theme-chooser.c +panels/sound/gvc-speaker-test.c +panels/sound/gvc-stream-status-icon.c +panels/sound/sound-theme-file-utils.c +panels/universal-access/cc-ua-panel.c +panels/universal-access/gnome-universal-access-panel.desktop.in.in +[type: gettext/glade]panels/universal-access/uap.ui +panels/universal-access/zoom-options.c +[type: gettext/glade]panels/universal-access/zoom-options.ui +[type: gettext/glade]panels/user-accounts/data/account-dialog.ui +[type: gettext/glade]panels/user-accounts/data/account-fingerprint.ui +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in +[type: gettext/glade]panels/user-accounts/data/password-dialog.ui +[type: gettext/glade]panels/user-accounts/data/photo-dialog.ui +[type: gettext/glade]panels/user-accounts/data/user-accounts-dialog.ui +panels/user-accounts/org.gnome.controlcenter.user-accounts.policy.in +panels/user-accounts/pw-utils.c +panels/user-accounts/run-passwd.c +panels/user-accounts/um-account-dialog.c +panels/user-accounts/um-account-type.c +panels/user-accounts/um-fingerprint-dialog.c +panels/user-accounts/um-password-dialog.c +panels/user-accounts/um-photo-dialog.c +panels/user-accounts/um-realm-manager.c +panels/user-accounts/um-user-manager.c +panels/user-accounts/um-user-panel.c +panels/user-accounts/um-utils.c +[type: gettext/glade]panels/wacom/button-mapping.ui +panels/wacom/calibrator/gui_gtk.c +panels/wacom/cc-wacom-mapping-panel.c +panels/wacom/cc-wacom-nav-button.c +panels/wacom/cc-wacom-page.c +panels/wacom/cc-wacom-stylus-page.c +panels/wacom/gnome-wacom-panel.desktop.in.in +[type: gettext/glade]panels/wacom/gnome-wacom-properties.ui +panels/wacom/gsd-wacom-device.c +[type: gettext/glade]panels/wacom/wacom-stylus-page.ui +shell/control-center.c +shell/gnomecc.directory.in +shell/gnome-control-center.desktop.in.in +[type: gettext/glade]shell/shell.ui diff -Nru gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.skip gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.skip --- gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.skip 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-rename-bluetooth-panel.patch/po/POTFILES.skip 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,21 @@ +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/bluetooth-properties.desktop.in +panels/color/gnome-color-panel.desktop.in +panels/datetime/gnome-datetime-panel.desktop.in +panels/display/gnome-display-panel.desktop.in +panels/info/gnome-info-panel.desktop.in +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/mouse/gnome-mouse-panel.desktop.in +panels/network/gnome-network-panel.desktop.in +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/power/gnome-power-panel.desktop.in +panels/printers/gnome-printers-panel.desktop.in +panels/region/gnome-region-panel.desktop.in +panels/screen/gnome-screen-panel.desktop.in +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/sounds/gnome-sounds-default.xml.in +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/fingerprint-strings.h +panels/wacom/gnome-wacom-panel.desktop.in +shell/gnome-control-center.desktop.in diff -Nru gnome-control-center-3.6.3/.pc/git_rename_natural_scrolling.patch/panels/mouse/gnome-mouse-properties.ui gnome-control-center-3.6.3/.pc/git_rename_natural_scrolling.patch/panels/mouse/gnome-mouse-properties.ui --- gnome-control-center-3.6.3/.pc/git_rename_natural_scrolling.patch/panels/mouse/gnome-mouse-properties.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_rename_natural_scrolling.patch/panels/mouse/gnome-mouse-properties.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,769 @@ + + + + + 1 + 10 + 6 + 1 + 1 + + + 1 + 10 + 6 + 1 + 1 + + + 100 + 1000 + 400 + 100 + 100 + + + False + 5 + Mouse Preferences + dialog + + + True + False + vertical + + + True + False + start + vertical + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + 10 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + 5 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + General + + + + + + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 20 + 20 + + + True + False + 220 + 2 + 3 + 40 + 10 + + + True + False + 5 + + + True + False + 1 + Slow + + + + + + False + False + 0 + + + + + True + True + adjustment4 + True + False + + + Double-click timeout + + + + + True + True + 1 + + + + + True + False + 0 + Fast + + + + + + False + False + 2 + + + + + 1 + 3 + 1 + 2 + 2 + + + + + True + False + start + 0 + _Double-click + True + center + double_click_scale + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + start + 0 + Primary _button + True + right_handed_radio + + + GTK_FILL + GTK_FILL + + + + + True + False + 10 + + + _Left + False + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + 0 + True + True + + + False + True + 0 + + + + + _Right + False + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + 0 + True + right_handed_radio + + + False + True + 1 + + + + + 1 + 3 + + + + + + + True + True + 1 + + + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + + + True + True + 0 + + + + + True + False + 10 + 5 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Mouse + + + + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 20 + 20 + + + True + False + 220 + 3 + 40 + 5 + + + True + False + start + 0 + _Pointer speed + True + center + pointer_speed_scale + + + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + False + 1 + Slow + center + + + + + + + False + True + 0 + + + + + True + True + adjustment1 + False + right + + + True + True + 1 + + + + + True + False + 0 + Fast + center + + + + + + + False + True + 2 + + + + + 1 + 3 + 2 + + + + + + + True + True + 2 + + + + + True + True + 2 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + False + + + True + True + 0 + + + + + True + False + 10 + 5 + 5 + + + True + False + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Touchpad + touchpad_enabled_switch + + + + + + False + False + 0 + + + + + False + True + True + end + False + + + True + True + 1 + + + + + + + True + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 20 + 20 + + + True + False + vertical + 15 + + + True + False + 220 + 3 + 40 + 5 + + + True + False + start + 0 + _Pointer speed + True + center + touchpad_pointer_speed_scale + + + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + False + 1 + Slow + center + + + + + + False + True + 0 + + + + + True + True + adjustment11 + False + right + + + True + True + 1 + + + + + True + False + 0 + Fast + center + + + + + + False + True + 2 + + + + + 1 + 3 + + 2 + + + + + False + True + 0 + + + + + True + False + 5 + 10 + + + Disable while _typing + False + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + none + True + 0 + True + True + + + 0 + 0 + 1 + 1 + + + + + Tap to _click + False + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + 0 + True + True + + + 0 + 1 + 1 + 1 + + + + + Two _finger scroll + False + True + True + False + False + True + 0 + True + + + 1 + 0 + 1 + 1 + + + + + C_ontent sticks to fingers + False + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + 0 + 0.49000000953674316 + True + True + + + 1 + 1 + 1 + 1 + + + + + False + True + 1 + + + + + + + False + False + 2 + + + + + True + True + 4 + + + + + False + False + 1 + + + + + False + False + 0 + + + + + True + False + end + + + gtk-help + False + True + True + True + False + False + True + + + False + False + 0 + + + + + gtk-close + False + True + True + True + False + False + True + + + False + False + 1 + + + + + False + True + end + 2 + + + + + + helpbutton1 + closebutton1 + + + diff -Nru gnome-control-center-3.6.3/.pc/git_restore_mouse_speed.patch/panels/mouse/gnome-mouse-properties.c gnome-control-center-3.6.3/.pc/git_restore_mouse_speed.patch/panels/mouse/gnome-mouse-properties.c --- gnome-control-center-3.6.3/.pc/git_restore_mouse_speed.patch/panels/mouse/gnome-mouse-properties.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_restore_mouse_speed.patch/panels/mouse/gnome-mouse-properties.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,303 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2001, 2012 Red Hat, Inc. + * Copyright (C) 2001 Ximian, Inc. + * + * Written by: Jonathon Blandford , + * Bradford Hovinen , + * Ondrej Holy , + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "gnome-mouse-properties.h" +#include "gsd-input-helper.h" + +#include +#include +#include + +#include +#include + +#define WID(x) (GtkWidget*) gtk_builder_get_object (dialog, x) + +static GSettings *mouse_settings = NULL; +static GSettings *touchpad_settings = NULL; +static GdkDeviceManager *device_manager = NULL; +static guint device_added_id = 0; +static guint device_removed_id = 0; +static gboolean changing_scroll = FALSE; + +static void +orientation_radio_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); +} + +static void +setup_scrollmethod_radios (GtkBuilder *dialog) +{ + GsdTouchpadScrollMethod method; + gboolean active; + + method = g_settings_get_enum (touchpad_settings, "scroll-method"); + active = (method == GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("two_finger_scroll_toggle")), active); +} + +static void +scrollmethod_changed_event (GtkToggleButton *button, GtkBuilder *dialog) +{ + GsdTouchpadScrollMethod method; + + if (changing_scroll) + return; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("two_finger_scroll_toggle")))) + method = GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING; + else + method = GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING; + + g_settings_set_enum (touchpad_settings, "scroll-method", method); +} + +static void +synaptics_check_capabilities (GtkBuilder *dialog) +{ + int numdevices, i; + XDeviceInfo *devicelist; + Atom realtype, prop; + int realformat; + unsigned long nitems, bytes_after; + unsigned char *data; + + prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", True); + if (!prop) + return; + + devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices); + for (i = 0; i < numdevices; i++) { + if (devicelist[i].use != IsXExtensionPointer) + continue; + + gdk_error_trap_push (); + XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), + devicelist[i].id); + if (gdk_error_trap_pop ()) + continue; + + gdk_error_trap_push (); + if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 2, False, + XA_INTEGER, &realtype, &realformat, &nitems, + &bytes_after, &data) == Success) && (realtype != None)) { + /* Property data is booleans for has_left, has_middle, has_right, has_double, has_triple. + * Newer drivers (X.org/kerrnel) will also include has_pressure and has_width. */ + if (!data[0]) { + gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE); + } + + /* Disable two finger scrolling unless the hardware supports + * double touch */ + if (!(data[3])) + gtk_widget_set_sensitive (WID ("two_finger_scroll_toggle"), FALSE); + + XFree (data); + } + gdk_error_trap_pop_ignored (); + + XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device); + } + XFreeDeviceList (devicelist); +} + +static void +pointer_speed_scale_event (GtkRange *scale, GtkBuilder *dialog) +{ + gdouble value; + GSettings *settings; + GtkAdjustment *adjustment; + + if (GTK_WIDGET (scale) == WID ("pointer_speed_scale")) + settings = mouse_settings; + else + settings = touchpad_settings; + + g_settings_set_double (settings, "motion-acceleration", gtk_range_get_value (scale)); + + adjustment = gtk_range_get_adjustment (scale); + value = gtk_adjustment_get_upper (adjustment) - gtk_range_get_value (scale) + 1; + g_settings_set_int (settings, "motion-threshold", value); +} + +/* Set up the property editors in the dialog. */ +static void +setup_dialog (GtkBuilder *dialog) +{ + GtkRadioButton *radio; + gboolean touchpad_present, mouse_present; + + /* Orientation radio buttons */ + radio = GTK_RADIO_BUTTON (WID ("left_handed_radio")); + g_settings_bind (mouse_settings, "left-handed", radio, "active", G_SETTINGS_BIND_DEFAULT); + + /* explicitly connect to button-release so that you can change orientation with either button */ + g_signal_connect (WID ("right_handed_radio"), "button_release_event", + G_CALLBACK (orientation_radio_button_release_event), NULL); + g_signal_connect (WID ("left_handed_radio"), "button_release_event", + G_CALLBACK (orientation_radio_button_release_event), NULL); + + /* Double-click time */ + g_settings_bind (mouse_settings, "double-click", + gtk_range_get_adjustment (GTK_RANGE (WID ("double_click_scale"))), "value", + G_SETTINGS_BIND_DEFAULT); + + /* Mouse section */ + mouse_present = mouse_is_present (); + gtk_widget_set_visible (WID ("mouse_vbox"), mouse_present); + + g_signal_connect (WID ("pointer_speed_scale"), "value-changed", + G_CALLBACK (pointer_speed_scale_event), dialog); + + /* Trackpad page */ + touchpad_present = touchpad_is_present (); + gtk_widget_set_visible (WID ("touchpad_vbox"), touchpad_present); + + g_settings_bind (touchpad_settings, "touchpad-enabled", + WID ("touchpad_enabled_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (touchpad_settings, "touchpad-enabled", + WID ("touchpad_options_box"), "sensitive", + G_SETTINGS_BIND_GET); + + g_settings_bind (touchpad_settings, "disable-while-typing", + WID ("disable_w_typing_toggle"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (touchpad_settings, "tap-to-click", + WID ("tap_to_click_toggle"), "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (touchpad_settings, "natural-scroll", + WID ("natural_scroll_toggle"), "active", + G_SETTINGS_BIND_DEFAULT); + + g_signal_connect (WID ("touchpad_pointer_speed_scale"), "value-changed", + G_CALLBACK (pointer_speed_scale_event), dialog); + + if (touchpad_present) { + synaptics_check_capabilities (dialog); + setup_scrollmethod_radios (dialog); + } + + g_signal_connect (WID ("two_finger_scroll_toggle"), "toggled", + G_CALLBACK (scrollmethod_changed_event), dialog); +} + +/* Construct the dialog */ + +static void +create_dialog (GtkBuilder *dialog) +{ + GtkSizeGroup *size_group; + + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_add_widget (size_group, WID ("primary_button_label")); + gtk_size_group_add_widget (size_group, WID ("pointer_speed_label")); + gtk_size_group_add_widget (size_group, WID ("double_click_label")); + gtk_size_group_add_widget (size_group, WID ("touchpad_pointer_speed_label")); + + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_add_widget (size_group, WID ("pointer_speed_fast_label")); + gtk_size_group_add_widget (size_group, WID ("double_click_fast_label")); + gtk_size_group_add_widget (size_group, WID ("touchpad_pointer_speed_fast_label")); + + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_add_widget (size_group, WID ("pointer_speed_slow_label")); + gtk_size_group_add_widget (size_group, WID ("double_click_slow_label")); + gtk_size_group_add_widget (size_group, WID ("touchpad_pointer_speed_slow_label")); + + gtk_widget_set_direction (WID ("primary_button_box"), GTK_TEXT_DIR_LTR); +} + +/* Callback issued when a button is clicked on the dialog */ + +static void +device_changed (GdkDeviceManager *device_manager, + GdkDevice *device, + GtkBuilder *dialog) +{ + gboolean present; + + present = touchpad_is_present (); + gtk_widget_set_visible (WID ("touchpad_vbox"), present); + + if (present) { + changing_scroll = TRUE; + synaptics_check_capabilities (dialog); + setup_scrollmethod_radios (dialog); + changing_scroll = FALSE; + } + + present = mouse_is_present (); + gtk_widget_set_visible (WID ("mouse_vbox"), present); +} + +GtkWidget * +gnome_mouse_properties_init (GtkBuilder *dialog) +{ + mouse_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.mouse"); + touchpad_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.touchpad"); + + device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); + device_added_id = g_signal_connect (device_manager, "device-added", + G_CALLBACK (device_changed), dialog); + device_removed_id = g_signal_connect (device_manager, "device-removed", + G_CALLBACK (device_changed), dialog); + + create_dialog (dialog); + setup_dialog (dialog); + + return WID ("mouse_properties_dialog"); +} + +void +gnome_mouse_properties_dispose (GtkWidget *widget) +{ + if (mouse_settings != NULL) { + g_object_unref (mouse_settings); + mouse_settings = NULL; + } + if (touchpad_settings != NULL) { + g_object_unref (touchpad_settings); + touchpad_settings = NULL; + } + if (device_manager != NULL) { + g_signal_handler_disconnect (device_manager, device_added_id); + device_added_id = 0; + g_signal_handler_disconnect (device_manager, device_removed_id); + device_removed_id = 0; + device_manager = NULL; + } +} diff -Nru gnome-control-center-3.6.3/.pc/git_set_a11y_wm_theme.patch/panels/universal-access/cc-ua-panel.c gnome-control-center-3.6.3/.pc/git_set_a11y_wm_theme.patch/panels/universal-access/cc-ua-panel.c --- gnome-control-center-3.6.3/.pc/git_set_a11y_wm_theme.patch/panels/universal-access/cc-ua-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_set_a11y_wm_theme.patch/panels/universal-access/cc-ua-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,699 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Thomas Wood + * Rodrigo Moya + * + */ + +#include + +#include +#include +#include +#include "cc-ua-panel.h" + +#include "zoom-options.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +#define DPI_FACTOR_LARGE 1.25 +#define DPI_FACTOR_NORMAL 1.0 + +#define HIGH_CONTRAST_THEME "HighContrast" +#define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" +#define KEY_GTK_THEME "gtk-theme" +#define KEY_ICON_THEME "icon-theme" + + +CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel) + +#define UA_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_UA_PANEL, CcUaPanelPrivate)) + +struct _CcUaPanelPrivate +{ + GtkBuilder *builder; + GSettings *wm_settings; + GSettings *interface_settings; + GSettings *kb_settings; + GSettings *mouse_settings; + GSettings *application_settings; + GSettings *mediakeys_settings; + + ZoomOptions *zoom_options; + guint shell_watch_id; +}; + + +static void +cc_ua_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_dispose (GObject *object) +{ + CcUaPanelPrivate *priv = CC_UA_PANEL (object)->priv; + + if (priv->shell_watch_id) + { + g_bus_unwatch_name (priv->shell_watch_id); + priv->shell_watch_id = 0; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->wm_settings) + { + g_object_unref (priv->wm_settings); + priv->wm_settings = NULL; + } + + if (priv->interface_settings) + { + g_object_unref (priv->interface_settings); + priv->interface_settings = NULL; + } + + if (priv->kb_settings) + { + g_object_unref (priv->kb_settings); + priv->kb_settings = NULL; + } + + if (priv->mouse_settings) + { + g_object_unref (priv->mouse_settings); + priv->mouse_settings = NULL; + } + + if (priv->application_settings) + { + g_object_unref (priv->application_settings); + priv->application_settings = NULL; + } + + if (priv->mediakeys_settings) + { + g_object_unref (priv->mediakeys_settings); + priv->mediakeys_settings = NULL; + } + + if (priv->zoom_options) + { + g_object_unref (priv->zoom_options); + priv->zoom_options = NULL; + } + + G_OBJECT_CLASS (cc_ua_panel_parent_class)->dispose (object); +} + +static void +cc_ua_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_ua_panel_parent_class)->finalize (object); +} + +static const char * +cc_ua_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/a11y"; + else + return "help:gnome-help/a11y"; +} + +static void +cc_ua_panel_class_init (CcUaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcUaPanelPrivate)); + + panel_class->get_help_uri = cc_ua_panel_get_help_uri; + + object_class->get_property = cc_ua_panel_get_property; + object_class->set_property = cc_ua_panel_set_property; + object_class->dispose = cc_ua_panel_dispose; + object_class->finalize = cc_ua_panel_finalize; +} + +static gchar *sticky_keys_section[] = { + "typing_sticky_keys_disable_two_keys_checkbutton", + "typing_sticky_keys_beep_modifier_checkbutton", + NULL +}; + +static gchar *slow_keys_section[]= { + "typing_slowkeys_delay_box", + "typing_slow_keys_beeb_box", + NULL +}; + +static gchar *bounce_keys_section[] = { + "typing_bouncekeys_delay_box", + "typing_bounce_keys_beep_rejected_checkbutton", + NULL +}; + +static gchar *secondary_click_section[] = { + "pointing_secondary_click_scale_box", + NULL +}; + +static gchar *dwell_click_section[] = { + "pointing_hover_click_delay_scale_box", + "pointing_hover_click_threshold_scale_box", + NULL +}; + +static gchar *visual_alerts_section[] = { + "hearing_test_flash_button", + "hearing_flash_window_title_button", + "hearing_flash_screen_button", + NULL +}; + +/* zoom options dialog */ +static void +zoom_options_launch_cb (GtkWidget *options_button, CcUaPanel *self) +{ + if (self->priv->zoom_options == NULL) + self->priv->zoom_options = zoom_options_new (); + + if (self->priv->zoom_options != NULL) + zoom_options_set_parent (self->priv->zoom_options, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); +} + +static void +cc_ua_panel_section_switched (GObject *object, + GParamSpec *pspec, + GtkBuilder *builder) +{ + GtkWidget *w; + gboolean enabled; + gchar **widgets, **s; + + widgets = g_object_get_data (object, "section-widgets"); + + g_object_get (object, "active", &enabled, NULL); + + for (s = widgets; *s; s++) + { + w = WID (builder, *s); + gtk_widget_set_sensitive (w, enabled); + } +} + +static void +settings_on_off_editor_new (CcUaPanelPrivate *priv, + GSettings *settings, + const gchar *key, + GtkWidget *widget, + gchar **section) +{ + /* set data to enable/disable the section this on/off switch controls */ + if (section) + { + g_object_set_data (G_OBJECT (widget), "section-widgets", section); + g_signal_connect (widget, "notify::active", + G_CALLBACK (cc_ua_panel_section_switched), + priv->builder); + } + + /* set up the boolean editor */ + g_settings_bind (settings, key, widget, "active", G_SETTINGS_BIND_DEFAULT); +} + +/* seeing section */ + +static void +cc_ua_panel_set_shortcut_label (CcUaPanel *self, + const char *label, + const char *key) +{ + GtkWidget *widget; + char *value; + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + widget = WID (self->priv->builder, label); + value = g_settings_get_string (self->priv->mediakeys_settings, key); + + if (value == NULL || *value == '\0') { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + g_free (value); + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +shell_vanished_cb (GDBusConnection *connection, + const gchar *name, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_hide (WID (priv->builder, "zoom_label_box")); + gtk_widget_hide (WID (priv->builder, "zoom_value_box")); +} + +static void +shell_appeared_cb (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_show (WID (priv->builder, "zoom_label_box")); + gtk_widget_show (WID (priv->builder, "zoom_value_box")); +} + +static gboolean +get_large_text_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + gdouble factor; + gboolean large; + + factor = g_variant_get_double (variant); + large = factor > DPI_FACTOR_NORMAL; + g_value_set_boolean (value, large); + + return TRUE; +} + +static GVariant * +set_large_text_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean large; + GSettings *settings = user_data; + GVariant *ret = NULL; + + large = g_value_get_boolean (value); + if (large) + ret = g_variant_new_double (DPI_FACTOR_LARGE); + else + g_settings_reset (settings, KEY_TEXT_SCALING_FACTOR); + + return ret; +} + +static gboolean +get_contrast_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + const char *theme; + gboolean hc; + + theme = g_variant_get_string (variant, NULL); + hc = (g_strcmp0 (theme, HIGH_CONTRAST_THEME) == 0); + g_value_set_boolean (value, hc); + + return TRUE; +} + +static GVariant * +set_contrast_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean hc; + GSettings *settings = user_data; + GVariant *ret = NULL; + + hc = g_value_get_boolean (value); + if (hc) + { + ret = g_variant_new_string (HIGH_CONTRAST_THEME); + g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); + } + else + { + g_settings_reset (settings, KEY_GTK_THEME); + g_settings_reset (settings, KEY_ICON_THEME); + } + + return ret; +} + +static void +cc_ua_panel_init_seeing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + g_settings_bind_with_mapping (priv->interface_settings, KEY_GTK_THEME, + WID (priv->builder, "seeing_contrast_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_contrast_mapping, + set_contrast_mapping, + priv->interface_settings, + NULL); + g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR, + WID (priv->builder, "seeing_large_text_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_large_text_mapping, + set_large_text_mapping, + priv->interface_settings, + NULL); + + g_settings_bind (priv->kb_settings, "togglekeys-enable", + WID (priv->builder, "seeing_toggle_keys_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) shell_appeared_cb, + (GBusNameVanishedCallback) shell_vanished_cb, + self, + NULL); + g_signal_connect (WID (priv->builder, "seeing_zoom_preferences_button"), + "clicked", + G_CALLBACK (zoom_options_launch_cb), self); + g_settings_bind (priv->application_settings, "screen-magnifier-enabled", + WID (priv->builder, "seeing_zoom_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + settings_on_off_editor_new (priv, priv->application_settings, + "screen-reader-enabled", + WID (priv->builder, "seeing_reader_switch"), + NULL); + + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_enable_keybinding_label", "magnifier"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_in_keybinding_label", "magnifier-zoom-in"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_out_keybinding_label", "magnifier-zoom-out"); + cc_ua_panel_set_shortcut_label (self, "seeing_reader_enable_keybinding_label", "screenreader"); +} + + +/* hearing/sound section */ +static void +visual_bell_type_notify_cb (GSettings *settings, + const gchar *key, + CcUaPanel *panel) +{ + GtkWidget *widget; + GDesktopVisualBellType type; + + type = g_settings_get_enum (panel->priv->wm_settings, "visual-bell-type"); + + if (type == G_DESKTOP_VISUAL_BELL_FRAME_FLASH) + widget = WID (panel->priv->builder, "hearing_flash_window_title_button"); + else + widget = WID (panel->priv->builder, "hearing_flash_screen_button"); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); +} + +static void +visual_bell_type_toggle_cb (GtkWidget *button, + CcUaPanel *panel) +{ + gboolean frame_flash; + GDesktopVisualBellType type; + + frame_flash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (frame_flash) + type = G_DESKTOP_VISUAL_BELL_FRAME_FLASH; + else + type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH; + g_settings_set_enum (panel->priv->wm_settings, "visual-bell-type", type); +} + +static gboolean +hearing_sound_preferences_clicked (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_hearing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* set the initial visual bell values */ + visual_bell_type_notify_cb (NULL, NULL, self); + + /* and listen */ + w = WID (priv->builder, "hearing_visual_alerts_switch"); + settings_on_off_editor_new (priv, priv->wm_settings, "visual-bell", w, visual_alerts_section); + + g_signal_connect (priv->wm_settings, "changed::visual-bell-type", + G_CALLBACK (visual_bell_type_notify_cb), self); + g_signal_connect (WID (priv->builder, "hearing_flash_window_title_button"), + "toggled", G_CALLBACK (visual_bell_type_toggle_cb), self); + + /* test flash */ + g_signal_connect (WID (priv->builder, "hearing_test_flash_button"), + "clicked", G_CALLBACK (gdk_beep), NULL); + + g_signal_connect (WID (priv->builder, "hearing_sound_preferences_link"), + "activate-link", + G_CALLBACK (hearing_sound_preferences_clicked), self); +} + +/* typing/keyboard section */ + +static void +cc_ua_panel_init_keyboard (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* Typing assistant (on-screen keyboard) */ + w = WID (priv->builder, "typing_assistant_switch"); + g_settings_bind (priv->application_settings, "screen-keyboard-enabled", + w, "active", G_SETTINGS_BIND_DEFAULT); + + /* enable shortcuts */ + w = WID (priv->builder, "typing_keyboard_toggle_switch"); + g_settings_bind (priv->kb_settings, "enable", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* sticky keys */ + w = WID (priv->builder, "typing_sticky_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "stickykeys-enable", w, sticky_keys_section); + + w = WID (priv->builder, "typing_sticky_keys_disable_two_keys_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-two-key-off", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + w = WID (priv->builder, "typing_sticky_keys_beep_modifier_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-modifier-beep", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + /* slow keys */ + w = WID (priv->builder, "typing_slow_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "slowkeys-enable", w, slow_keys_section); + + w = WID (priv->builder, "typing_slowkeys_delay_scale"); + g_settings_bind (priv->kb_settings, "slowkeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_pressed_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-press", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_accepted_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-accept", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-reject", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* bounce keys */ + w = WID (priv->builder, "typing_bounce_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "bouncekeys-enable", w, bounce_keys_section); + + w = WID (priv->builder, "typing_bouncekeys_delay_scale"); + g_settings_bind (priv->kb_settings, "bouncekeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_bounce_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "bouncekeys-beep-reject", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); +} + +/* mouse/pointing & clicking section */ +static gboolean +pointing_mouse_preferences_clicked_cb (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "mouse", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_mouse (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* mouse keys */ + w = WID (priv->builder, "pointing_mouse_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "mousekeys-enable", w, NULL); + + /* simulated secondary click */ + w = WID (priv->builder, "pointing_second_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "secondary-click-enabled", w, secondary_click_section); + + w = WID (priv->builder, "pointing_secondary_click_delay_scale"); + g_settings_bind (priv->mouse_settings, "secondary-click-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* dwell click */ + w = WID (priv->builder, "pointing_hover_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "dwell-click-enabled", w, dwell_click_section); + + w = WID (priv->builder, "pointing_dwell_delay_scale"); + g_settings_bind (priv->mouse_settings, "dwell-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "pointing_dwell_threshold_scale"); + g_settings_bind (priv->mouse_settings, "dwell-threshold", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* mouse preferences button */ + g_signal_connect (WID (priv->builder, "pointing_mouse_preferences_link"), + "activate-link", + G_CALLBACK (pointing_mouse_preferences_clicked_cb), self); +} + +static void +cc_ua_panel_init (CcUaPanel *self) +{ + CcUaPanelPrivate *priv; + GtkWidget *widget; + GError *err = NULL; + gchar *objects[] = { "universal_access_box", "contrast_model", + "text_size_model", "slowkeys_delay_adjustment", + "bouncekeys_delay_adjustment", "click_delay_adjustment", + "dwell_time_adjustment", "dwell_threshold_adjustment", + "seeing_sizegroup", "typing_sizegroup", + "pointing_sizegroup", "pointing_sizegroup2", + "pointing_scale_sizegroup", "sizegroup1", + "hearing_sizegroup", + NULL }; + + priv = self->priv = UA_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_objects_from_file (priv->builder, + GNOMECC_UI_DIR "/uap.ui", + objects, + &err); + + if (err) + { + g_warning ("Could not load interface file: %s", err->message); + g_error_free (err); + + g_object_unref (priv->builder); + priv->builder = NULL; + + return; + } + + priv->interface_settings = g_settings_new ("org.gnome.desktop.interface"); + priv->wm_settings = g_settings_new ("org.gnome.desktop.wm.preferences"); + priv->kb_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard"); + priv->mouse_settings = g_settings_new ("org.gnome.desktop.a11y.mouse"); + priv->application_settings = g_settings_new ("org.gnome.desktop.a11y.applications"); + priv->mediakeys_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + + cc_ua_panel_init_keyboard (self); + cc_ua_panel_init_mouse (self); + cc_ua_panel_init_hearing (self); + cc_ua_panel_init_seeing (self); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, + "universal_access_box"); + + gtk_container_add (GTK_CONTAINER (self), widget); +} + +void +cc_ua_panel_register (GIOModule *module) +{ + cc_ua_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_UA_PANEL, + "universal-access", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/git_shell_use_view_style_class.patch/shell/shell.ui gnome-control-center-3.6.3/.pc/git_shell_use_view_style_class.patch/shell/shell.ui --- gnome-control-center-3.6.3/.pc/git_shell_use_view_style_class.patch/shell/shell.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_shell_use_view_style_class.patch/shell/shell.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,152 @@ + + + + + + System Settings + False + preferences-desktop + center + + + True + vertical + + + True + + + + True + + + + True + 5 + 5 + 10 + 5 + + + True + + + True + 1 + 0 + + + True + horizontal + + + 210 + True + True + + edit-find-symbolic + False + False + + + + + False + True + + + + + + + 0 + + + + + + + + + True + True + + + + + False + 0 + + + + + True + True + False + + + True + True + never + automatic + in + + + True + queue + none + + + True + vertical + + + + + + + + + + + + True + True + automatic + automatic + in + + + + + + + + 1 + + + + + + + + + + + + + + + + + True + False + view-grid-symbolic + True + 16 + + diff -Nru gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel-input.c gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel-input.c --- gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel-input.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel-input.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1568 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by: Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include + +#include +#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#ifdef HAVE_IBUS +#include +#endif + +#include "gdm-languages.h" +#include "gnome-region-panel-input.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s)) + +#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" + +#define KEY_CURRENT_INPUT_SOURCE "current" +#define KEY_INPUT_SOURCES "sources" + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +enum { + NAME_COLUMN, + TYPE_COLUMN, + ID_COLUMN, + SETUP_COLUMN, + N_COLUMNS +}; + +static GSettings *input_sources_settings = NULL; +static GnomeXkbInfo *xkb_info = NULL; +static GtkWidget *input_chooser = NULL; /* weak pointer */ + +#ifdef HAVE_IBUS +static IBusBus *ibus = NULL; +static GHashTable *ibus_engines = NULL; +static GCancellable *ibus_cancellable = NULL; +static guint shell_name_watch_id = 0; + +static const gchar *supported_ibus_engines[] = { + /* Simplified Chinese */ + "pinyin", + "bopomofo", + "wubi", + "erbi", + /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ + "libpinyin", + "libbopomofo", + + /* Traditional Chinese */ + /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ + "chewing", + "cangjie5", + "cangjie3", + "quick5", + "quick3", + "stroke5", + + /* Japanese */ + "anthy", + "mozc-jp", + "skk", + + /* Korean */ + "hangul", + + /* Thai */ + "m17n:th:kesmanee", + "m17n:th:pattachote", + "m17n:th:tis820", + + /* Vietnamese */ + "m17n:vi:tcvn", + "m17n:vi:telex", + "m17n:vi:viqr", + "m17n:vi:vni", + "Unikey", + + /* Sinhala */ + "m17n:si:wijesekera", + "m17n:si:phonetic-dynamic", + "m17n:si:trans", + "sayura", + + /* Indic */ + /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ + + /* Assamese */ + "m17n:as:phonetic", + "m17n:as:inscript", + "m17n:as:itrans", + + /* Bengali */ + "m17n:bn:inscript", + "m17n:bn:itrans", + "m17n:bn:probhat", + + /* Gujarati */ + "m17n:gu:inscript", + "m17n:gu:itrans", + "m17n:gu:phonetic", + + /* Hindi */ + "m17n:hi:inscript", + "m17n:hi:itrans", + "m17n:hi:phonetic", + "m17n:hi:remington", + "m17n:hi:typewriter", + "m17n:hi:vedmata", + + /* Kannada */ + "m17n:kn:kgp", + "m17n:kn:inscript", + "m17n:kn:itrans", + + /* Kashmiri */ + "m17n:ks:inscript", + + /* Maithili */ + "m17n:mai:inscript", + + /* Malayalam */ + "m17n:ml:inscript", + "m17n:ml:itrans", + "m17n:ml:mozhi", + "m17n:ml:swanalekha", + + /* Marathi */ + "m17n:mr:inscript", + "m17n:mr:itrans", + "m17n:mr:phonetic", + + /* Nepali */ + "m17n:ne:rom", + "m17n:ne:trad", + + /* Oriya */ + "m17n:or:inscript", + "m17n:or:itrans", + "m17n:or:phonetic", + + /* Punjabi */ + "m17n:pa:inscript", + "m17n:pa:itrans", + "m17n:pa:phonetic", + "m17n:pa:jhelum", + + /* Sanskrit */ + "m17n:sa:harvard-kyoto", + + /* Sindhi */ + "m17n:sd:inscript", + + /* Tamil */ + "m17n:ta:tamil99", + "m17n:ta:inscript", + "m17n:ta:itrans", + "m17n:ta:phonetic", + "m17n:ta:lk-renganathan", + "m17n:ta:vutam", + "m17n:ta:typewriter", + + /* Telugu */ + "m17n:te:inscript", + "m17n:te:apple", + "m17n:te:pothana", + "m17n:te:rts", + + /* Urdu */ + "m17n:ur:phonetic", + + /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ + "m17n:as:inscript2", + "m17n:bn:inscript2", + "m17n:brx:inscript2-deva", + "m17n:doi:inscript2-deva", + "m17n:gu:inscript2", + "m17n:hi:inscript2", + "m17n:kn:inscript2", + "m17n:kok:inscript2-deva", + "m17n:mai:inscript2", + "m17n:ml:inscript2", + "m17n:mni:inscript2-beng", + "m17n:mni:inscript2-mtei", + "m17n:mr:inscript2", + "m17n:ne:inscript2-deva", + "m17n:or:inscript2", + "m17n:pa:inscript2-guru", + "m17n:sa:inscript2", + "m17n:sat:inscript2-deva", + "m17n:sat:inscript2-olck", + "m17n:sd:inscript2-deva", + "m17n:ta:inscript2", + "m17n:te:inscript2", + + /* No corresponding XKB map available for the languages */ + + /* Chinese Yi */ + "m17n:ii:phonetic", + + /* Tai-Viet */ + "m17n:tai:sonla", + + /* Kazakh in Arabic script */ + "m17n:kk:arabic", + + /* Yiddish */ + "m17n:yi:yivo", + + /* Canadian Aboriginal languages */ + "m17n:ath:phonetic", + "m17n:bla:phonetic", + "m17n:cr:western", + "m17n:iu:phonetic", + "m17n:nsk:phonetic", + "m17n:oj:phonetic", + + /* Non-trivial engines, like transliteration-based instead of + keymap-based. Confirmation needed that the engines below are + actually used by local language users. */ + + /* Tibetan */ + "m17n:bo:ewts", + "m17n:bo:tcrc", + "m17n:bo:wylie", + + /* Esperanto */ + "m17n:eo:h-f", + "m17n:eo:h", + "m17n:eo:plena", + "m17n:eo:q", + "m17n:eo:vi", + "m17n:eo:x", + + /* Amharic */ + "m17n:am:sera", + + /* Russian */ + "m17n:ru:translit", + + /* Classical Greek */ + "m17n:grc:mizuochi", + + /* Lao */ + "m17n:lo:lrt", + + /* Postfix modifier input methods */ + "m17n:da:post", + "m17n:sv:post", + NULL +}; +#endif /* HAVE_IBUS */ + +static void populate_model (GtkListStore *store, + GtkListStore *active_sources_store); +static GtkWidget *input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources); +static gboolean input_chooser_get_selected (GtkWidget *chooser, + GtkTreeModel **model, + GtkTreeIter *iter); +static GtkTreeModel *tree_view_get_actual_model (GtkTreeView *tv); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +#ifdef HAVE_IBUS +static void +clear_ibus (void) +{ + if (shell_name_watch_id > 0) + { + g_bus_unwatch_name (shell_name_watch_id); + shell_name_watch_id = 0; + } + g_cancellable_cancel (ibus_cancellable); + g_clear_object (&ibus_cancellable); + g_clear_pointer (&ibus_engines, g_hash_table_destroy); + g_clear_object (&ibus); +} + +static gchar * +engine_get_display_name (IBusEngineDesc *engine_desc) +{ + const gchar *name; + const gchar *language_code; + const gchar *language; + gchar *display_name; + + name = ibus_engine_desc_get_longname (engine_desc); + language_code = ibus_engine_desc_get_language (engine_desc); + language = ibus_get_language_name (language_code); + + display_name = g_strdup_printf ("%s (%s)", language, name); + + return display_name; +} + +static GDesktopAppInfo * +setup_app_info_for_id (const gchar *id) +{ + GDesktopAppInfo *app_info; + gchar *desktop_file_name; + gchar **strv; + + strv = g_strsplit (id, ":", 2); + desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]); + g_strfreev (strv); + + app_info = g_desktop_app_info_new (desktop_file_name); + g_free (desktop_file_name); + + return app_info; +} + +static void +input_chooser_repopulate (GtkListStore *active_sources_store) +{ + GtkBuilder *builder; + GtkListStore *model; + + if (!input_chooser) + return; + + builder = g_object_get_data (G_OBJECT (input_chooser), "builder"); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + gtk_list_store_clear (model); + populate_model (model, active_sources_store); +} + +static void +update_ibus_active_sources (GtkBuilder *builder) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type, *id; + gboolean ret; + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + model = tree_view_get_actual_model (tv); + + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { + IBusEngineDesc *engine_desc = NULL; + GDesktopAppInfo *app_info = NULL; + gchar *display_name = NULL; + + engine_desc = g_hash_table_lookup (ibus_engines, id); + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + NAME_COLUMN, display_name, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + } + + g_free (type); + g_free (id); + + ret = gtk_tree_model_iter_next (model, &iter); + } + + input_chooser_repopulate (GTK_LIST_STORE (model)); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + GtkBuilder *builder) +{ + gboolean show_all_sources; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (ibus, result, &error); + + g_clear_object (&ibus_cancellable); + + if (!list && error) + { + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + show_all_sources = g_settings_get_boolean (input_sources_settings, "show-all-sources"); + + /* Maps engine ids to engine description objects */ + ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) + { + IBusEngineDesc *engine = l->data; + const gchar *engine_id = ibus_engine_desc_get_name (engine); + + if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); + else + g_object_unref (engine); + } + g_list_free (list); + + update_ibus_active_sources (builder); +} + +static void +fetch_ibus_engines (GtkBuilder *builder) +{ + ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (ibus, + -1, + ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + builder); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (ibus, fetch_ibus_engines, builder); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} + +static void +on_shell_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer data) +{ + GtkBuilder *builder = data; + + if (!ibus) + { + ibus = ibus_bus_new_async (); + if (ibus_bus_is_connected (ibus)) + fetch_ibus_engines (builder); + else + g_signal_connect_swapped (ibus, "connected", + G_CALLBACK (fetch_ibus_engines), builder); + } + maybe_start_ibus (); +} +#endif /* HAVE_IBUS */ + +static gboolean +add_source_to_table (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GHashTable *hash = data; + gchar *type; + gchar *id; + + gtk_tree_model_get (model, iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + g_hash_table_add (hash, g_strconcat (type, id, NULL)); + + g_free (type); + g_free (id); + + return FALSE; +} + +static void +populate_model (GtkListStore *store, + GtkListStore *active_sources_store) +{ + GHashTable *active_sources_table; + GtkTreeIter iter; + const gchar *name; + GList *sources, *tmp; + gchar *source_id = NULL; + + active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources_store), + add_source_to_table, + active_sources_table); + + sources = gnome_xkb_info_get_all_layouts (xkb_info); + + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_XKB, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data, + &name, NULL, NULL, NULL); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB, + ID_COLUMN, tmp->data, + -1); + } + g_free (source_id); + + g_list_free (sources); + +#ifdef HAVE_IBUS + if (ibus_engines) + { + gchar *display_name; + + sources = g_hash_table_get_keys (ibus_engines); + + source_id = NULL; + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_IBUS, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS, + ID_COLUMN, tmp->data, + -1); + g_free (display_name); + } + g_free (source_id); + + g_list_free (sources); + } +#endif + + g_hash_table_destroy (active_sources_table); +} + +static void +populate_with_active_sources (GtkListStore *store) +{ + GVariant *sources; + GVariantIter iter; + const gchar *name; + const gchar *type; + const gchar *id; + gchar *display_name; + GDesktopAppInfo *app_info; + GtkTreeIter tree_iter; + + sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) + { + display_name = NULL; + app_info = NULL; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (!name) + { + g_warning ("Couldn't find XKB input source '%s'", id); + continue; + } + display_name = g_strdup (name); + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + continue; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + continue; + } + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set (store, &tree_iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + + g_variant_unref (sources); +} + +static void +update_configuration (GtkTreeModel *model) +{ + GtkTreeIter iter; + gchar *type; + gchar *id; + GVariantBuilder builder; + GVariant *old_sources; + const gchar *old_current_type; + const gchar *old_current_id; + guint old_current_index; + guint old_n_sources; + guint index; + + old_sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + old_current_index = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE); + old_n_sources = g_variant_n_children (old_sources); + + if (old_n_sources > 0 && old_current_index < old_n_sources) + { + g_variant_get_child (old_sources, + old_current_index, + "(&s&s)", + &old_current_type, + &old_current_id); + } + else + { + old_current_type = ""; + old_current_id = ""; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); + index = 0; + gtk_tree_model_get_iter_first (model, &iter); + do + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + if (index != old_current_index && + g_str_equal (type, old_current_type) && + g_str_equal (id, old_current_id)) + { + g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, index); + } + g_variant_builder_add (&builder, "(ss)", type, id); + g_free (type); + g_free (id); + index += 1; + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); + g_settings_apply (input_sources_settings); + + g_variant_unref (old_sources); +} + +static gboolean +get_selected_iter (GtkBuilder *builder, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + return gtk_tree_selection_get_selected (selection, model, iter); +} + +static gint +idx_from_model_iter (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gint idx; + + path = gtk_tree_model_get_path (model, iter); + if (path == NULL) + return -1; + + idx = gtk_tree_path_get_indices (path)[0]; + gtk_tree_path_free (path); + + return idx; +} + +static void +update_button_sensitivity (GtkBuilder *builder) +{ + GtkWidget *remove_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *show_button; + GtkWidget *settings_button; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gint n_active; + gint index; + gboolean settings_sensitive; + GDesktopAppInfo *app_info; + + remove_button = WID("input_source_remove"); + show_button = WID("input_source_show"); + up_button = WID("input_source_move_up"); + down_button = WID("input_source_move_down"); + settings_button = WID("input_source_settings"); + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL); + + if (get_selected_iter (builder, &model, &iter)) + { + index = idx_from_model_iter (model, &iter); + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + } + else + { + index = -1; + app_info = NULL; + } + + settings_sensitive = (index >= 0 && app_info != NULL); + + if (app_info) + g_object_unref (app_info); + + gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1); + gtk_widget_set_sensitive (show_button, index >= 0); + gtk_widget_set_sensitive (up_button, index > 0); + gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); + gtk_widget_set_sensitive (settings_button, settings_sensitive); +} + +static void +set_selected_path (GtkBuilder *builder, + GtkTreePath *path) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + gtk_tree_selection_select_path (selection, path); +} + +static GtkTreeModel * +tree_view_get_actual_model (GtkTreeView *tv) +{ + GtkTreeModel *filtered_store; + + filtered_store = gtk_tree_view_get_model (tv); + + return gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered_store)); +} + +static void +chooser_response (GtkWidget *chooser, gint response_id, gpointer data) +{ + GtkBuilder *builder = data; + + if (response_id == GTK_RESPONSE_OK) + { + GtkTreeModel *model; + GtkTreeIter iter; + + if (input_chooser_get_selected (chooser, &model, &iter)) + { + GtkTreeView *tv; + GtkListStore *child_model; + GtkTreeIter child_iter, filter_iter; + gchar *name; + gchar *type; + gchar *id; + GDesktopAppInfo *app_info = NULL; + + gtk_tree_model_get (model, &iter, + NAME_COLUMN, &name, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + +#ifdef HAVE_IBUS + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + app_info = setup_app_info_for_id (id); +#endif + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + child_model = GTK_LIST_STORE (tree_view_get_actual_model (tv)); + + gtk_list_store_append (child_model, &child_iter); + + gtk_list_store_set (child_model, &child_iter, + NAME_COLUMN, name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (name); + g_free (type); + g_free (id); + if (app_info) + g_object_unref (app_info); + + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tv)), + &filter_iter, + &child_iter); + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tv), &filter_iter); + + update_button_sensitivity (builder); + update_configuration (GTK_TREE_MODEL (child_model)); + } + else + { + g_debug ("nothing selected, nothing added"); + } + } + + gtk_widget_destroy (GTK_WIDGET (chooser)); +} + +static void +add_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkWidget *chooser; + GtkWidget *toplevel; + GtkWidget *treeview; + GtkListStore *active_sources; + + g_debug ("add an input source"); + + toplevel = gtk_widget_get_toplevel (WID ("region_notebook")); + treeview = WID ("active_input_sources"); + active_sources = GTK_LIST_STORE (tree_view_get_actual_model (GTK_TREE_VIEW (treeview))); + + chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources); + g_signal_connect (chooser, "response", + G_CALLBACK (chooser_response), builder); +} + +static void +remove_selected_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter child_iter; + GtkTreePath *path; + + g_debug ("remove selected input source"); + + if (get_selected_iter (builder, &model, &iter) == FALSE) + return; + + path = gtk_tree_model_get_path (model, &iter); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_list_store_remove (GTK_LIST_STORE (child_model), &child_iter); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + gtk_tree_path_prev (path); + + set_selected_path (builder, path); + + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_up (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, prev; + GtkTreeIter child_iter, child_prev; + GtkTreePath *path; + + g_debug ("move selected input source up"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + prev = iter; + if (!gtk_tree_model_iter_previous (model, &prev)) + return; + + path = gtk_tree_model_get_path (model, &prev); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_prev, + &prev); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_prev); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_down (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, next; + GtkTreeIter child_iter, child_next; + GtkTreePath *path; + + g_debug ("move selected input source down"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + next = iter; + if (!gtk_tree_model_iter_next (model, &next)) + return; + + path = gtk_tree_model_get_path (model, &next); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_next, + &next); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_next); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +show_selected_layout (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *id; + gchar *kbd_viewer_args; + const gchar *xkb_layout; + const gchar *xkb_variant; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + gnome_xkb_info_get_layout_info (xkb_info, id, NULL, NULL, &xkb_layout, &xkb_variant); + + if (!xkb_layout || !xkb_layout[0]) + { + g_warning ("Couldn't find XKB input source '%s'", id); + goto exit; + } + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + xkb_layout = ibus_engine_desc_get_layout (engine_desc); + xkb_variant = ""; + } + else + { + g_warning ("Couldn't find IBus input source '%s'", id); + goto exit; + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + goto exit; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + goto exit; + } + + if (xkb_variant[0]) + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", + xkb_layout, xkb_variant); + else + kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", + xkb_layout); + + g_spawn_command_line_async (kbd_viewer_args, NULL); + + g_free (kbd_viewer_args); + exit: + g_free (type); + g_free (id); +} + +static void +show_selected_settings (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + GdkAppLaunchContext *ctx; + GDesktopAppInfo *app_info; + gchar *id; + GError *error = NULL; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + + if (!app_info) + return; + + ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); + gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ()); + + gtk_tree_model_get (model, &iter, ID_COLUMN, &id, -1); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx), + "IBUS_ENGINE_NAME", + id); + g_free (id); + + if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) + { + g_warning ("Failed to launch input source setup: %s", error->message); + g_error_free (error); + } + + g_object_unref (ctx); + g_object_unref (app_info); +} + +static gboolean +go_to_shortcuts (GtkLinkButton *button, + CcRegionPanel *panel) +{ + CcShell *shell; + const gchar *argv[] = { "shortcuts", "Typing", NULL }; + GError *error = NULL; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error)) + { + g_warning ("Failed to activate Keyboard panel: %s", error->message); + g_error_free (error); + } + + return TRUE; +} + +static void +input_sources_changed (GSettings *settings, + gchar *key, + GtkBuilder *builder) +{ + GtkWidget *treeview; + GtkTreeModel *store; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeModel *model; + + treeview = WID("active_input_sources"); + store = tree_view_get_actual_model (GTK_TREE_VIEW (treeview)); + + if (get_selected_iter (builder, &model, &iter)) + path = gtk_tree_model_get_path (model, &iter); + else + path = NULL; + + gtk_list_store_clear (GTK_LIST_STORE (store)); + populate_with_active_sources (GTK_LIST_STORE (store)); + + if (path) + { + set_selected_path (builder, path); + gtk_tree_path_free (path); + } +} + +static void +update_shortcut_label (GtkWidget *widget, + const char *value) +{ + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + if (value == NULL || *value == '\0') + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +update_shortcuts (GtkBuilder *builder) +{ + char *previous, *next; + GSettings *settings; + + settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + + previous = g_settings_get_string (settings, "switch-input-source-backward"); + next = g_settings_get_string (settings, "switch-input-source"); + + update_shortcut_label (WID ("prev-source-shortcut-label"), previous); + update_shortcut_label (WID ("next-source-shortcut-label"), next); + + g_free (previous); + g_free (next); +} + +static gboolean +active_sources_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *display_name; + + gtk_tree_model_get (model, iter, NAME_COLUMN, &display_name, -1); + + if (!display_name) + return FALSE; + + g_free (display_name); + + return TRUE; +} + +void +setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *panel) +{ + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkListStore *store; + GtkTreeModel *filtered_store; + GtkTreeSelection *selection; + + /* set up the list of active inputs */ + treeview = WID("active_input_sources"); + column = gtk_tree_view_column_new (); + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_DESKTOP_APP_INFO); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); + g_settings_delay (input_sources_settings); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) g_object_unref, input_sources_settings); + + if (!xkb_info) + xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + builder, + NULL); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) clear_ibus, NULL); +#endif + + populate_with_active_sources (store); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect_swapped (selection, "changed", + G_CALLBACK (update_button_sensitivity), builder); + + /* Some input source types might have their info loaded + * asynchronously. In that case we don't want to show them + * immediately so we use a filter model on top of the real model + * which mirrors the GSettings key. */ + filtered_store = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered_store), + active_sources_visible_func, + NULL, + NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), filtered_store); + + /* set up the buttons */ + g_signal_connect (WID("input_source_add"), "clicked", + G_CALLBACK (add_input), builder); + g_signal_connect (WID("input_source_remove"), "clicked", + G_CALLBACK (remove_selected_input), builder); + g_signal_connect (WID("input_source_move_up"), "clicked", + G_CALLBACK (move_selected_input_up), builder); + g_signal_connect (WID("input_source_move_down"), "clicked", + G_CALLBACK (move_selected_input_down), builder); + g_signal_connect (WID("input_source_show"), "clicked", + G_CALLBACK (show_selected_layout), builder); + g_signal_connect (WID("input_source_settings"), "clicked", + G_CALLBACK (show_selected_settings), builder); + + /* use an em dash is no shortcut */ + update_shortcuts (builder); + + g_signal_connect (WID("jump-to-shortcuts"), "activate-link", + G_CALLBACK (go_to_shortcuts), panel); + + g_signal_connect (G_OBJECT (input_sources_settings), + "changed::" KEY_INPUT_SOURCES, + G_CALLBACK (input_sources_changed), + builder); +} + +static void +filter_clear (GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + gpointer user_data) +{ + gtk_entry_set_text (entry, ""); +} + +static gchar **search_pattern_list; + +static void +filter_changed (GtkBuilder *builder) +{ + GtkTreeModelFilter *filtered_model; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreeIter selected_iter; + GtkWidget *filter_entry; + const gchar *pattern; + gchar *upattern; + + filter_entry = WID ("input_source_filter"); + pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry)); + upattern = g_utf8_strup (pattern, -1); + if (!g_strcmp0 (pattern, "")) + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-find-symbolic", + "secondary-icon-activatable", FALSE, + "secondary-icon-sensitive", FALSE, + NULL); + else + g_object_set (G_OBJECT (filter_entry), + "secondary-icon-name", "edit-clear-symbolic", + "secondary-icon-activatable", TRUE, + "secondary-icon-sensitive", TRUE, + NULL); + + if (search_pattern_list != NULL) + g_strfreev (search_pattern_list); + + search_pattern_list = g_strsplit (upattern, " ", -1); + g_free (upattern); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + gtk_tree_model_filter_refilter (filtered_model); + + tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list")); + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model), + &selected_iter); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free (path); + } + else + { + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkBuilder *builder) +{ + gtk_widget_set_sensitive (WID ("ok-button"), + gtk_tree_selection_get_selected (selection, NULL, NULL)); +} + +static void +row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + GtkBuilder *builder) +{ + GtkWidget *add_button; + GtkWidget *dialog; + + add_button = WID ("ok-button"); + dialog = WID ("input_source_chooser"); + if (gtk_widget_is_sensitive (add_button)) + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +entry_activated (GtkBuilder *builder, + gpointer data) +{ + row_activated (NULL, NULL, NULL, builder); +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name = NULL; + gchar **pattern; + gboolean rv = TRUE; + + if (search_pattern_list == NULL || search_pattern_list[0] == NULL) + return TRUE; + + gtk_tree_model_get (model, iter, + NAME_COLUMN, &name, + -1); + + pattern = search_pattern_list; + do { + gboolean is_pattern_found = FALSE; + gchar *udesc = g_utf8_strup (name, -1); + if (udesc != NULL && g_strstr_len (udesc, -1, *pattern)) + { + is_pattern_found = TRUE; + } + g_free (udesc); + + if (!is_pattern_found) + { + rv = FALSE; + break; + } + + } while (*++pattern != NULL); + + g_free (name); + + return rv; +} + +static GtkWidget * +input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources) +{ + GtkBuilder *builder; + GtkWidget *chooser; + GtkWidget *filtered_list; + GtkWidget *filter_entry; + GtkTreeViewColumn *visible_column; + GtkTreeSelection *selection; + GtkListStore *model; + GtkTreeModelFilter *filtered_model; + GtkTreeIter iter; + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, + GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui", + NULL); + chooser = WID ("input_source_chooser"); + input_chooser = chooser; + g_object_add_weak_pointer (G_OBJECT (chooser), (gpointer *) &input_chooser); + g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref); + + filtered_list = WID ("filtered_input_source_list"); + filter_entry = WID ("input_source_filter"); + + g_object_set_data (G_OBJECT (chooser), + "filtered_input_source_list", filtered_list); + visible_column = + gtk_tree_view_column_new_with_attributes ("Input Sources", + gtk_cell_renderer_text_new (), + "text", NAME_COLUMN, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window); + + gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list), + visible_column); + /* We handle searching ourselves, thank you. */ + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1); + + g_signal_connect_swapped (G_OBJECT (filter_entry), "activate", + G_CALLBACK (entry_activated), builder); + g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text", + G_CALLBACK (filter_changed), builder); + + g_signal_connect (G_OBJECT (filter_entry), "icon-release", + G_CALLBACK (filter_clear), NULL); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + populate_model (model, active_sources); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + NAME_COLUMN, GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (filtered_model, + filter_func, + NULL, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list)); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), builder); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + + g_signal_connect (G_OBJECT (filtered_list), "row-activated", + G_CALLBACK (row_activated), builder); + + gtk_widget_grab_focus (filter_entry); + + gtk_widget_show (chooser); + + return chooser; +} + +static gboolean +input_chooser_get_selected (GtkWidget *dialog, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkWidget *tv; + GtkTreeSelection *selection; + + tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list"); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + + return gtk_tree_selection_get_selected (selection, model, iter); +} diff -Nru gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel.ui gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel.ui --- gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git_show_per_window_input_settings.patch/panels/region/gnome-region-panel.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1352 @@ + + + + + 100 + 2000 + 500 + 10 + 10 + + + 1 + 100000 + 1 + 1 + 10 + + + 10 + 110 + 30 + 10 + 10 + + + 100 + 2500 + 1000 + 200 + 200 + + + 500 + 0.5 + 10 + 10 + + + 900 + 0.5 + 10 + 10 + + + 3000 + 1800 + 10 + 10 + + + 10 + 1000 + 300 + 10 + 10 + + + 10 + 2000 + 300 + 10 + 10 + + + 1 + 100000 + 1 + 1 + 10 + + + + False + 5 + Region and Language + 600 + 430 + dialog + + + True + False + vertical + 2 + + + False + + + False + True + end + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 12 + + + True + True + 10 + + + True + False + 12 + 12 + + + True + False + 0 + Select a display language (change will be applied next time you log in) + + + False + True + 0 + + + + + True + False + vertical + + + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + False + False + icons + False + 1 + + + + + False + True + Add Language + False + True + list-add-symbolic + + + False + True + + + + + False + True + 1 + + + + + False + + + True + False + True + Add Language + + + True + True + 0 + + + + + Install languages... + True + True + True + True + + + False + True + 1 + + + + + False + True + 1 + + + + + True + True + 1 + + + + + + + True + False + Language + + + False + + + + + True + False + 12 + 12 + 12 + 12 + 6 + 12 + + + True + False + start + Select a region (change will be applied the next time you log in) + + + 0 + 0 + 2 + 1 + + + + + True + False + vertical + + + True + True + True + never + in + + + True + True + False + + + + + + + + True + True + 0 + + + + + icons + False + 1 + True + + + + False + Add Region + True + False + True + list-add-symbolic + + + False + True + + + + + False + True + Remove Region + False + False + True + list-remove-symbolic + + + False + True + + + + + False + True + 1 + + + + + 0 + 1 + 1 + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 9 + 2 + + + True + False + 0 + Dates + + + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 3 + 4 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Times + + + 4 + 5 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 4 + 5 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 5 + 6 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Numbers + + + 6 + 7 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 6 + 7 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Currency + + + 7 + 8 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 7 + 8 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + Measurement + + + 8 + 9 + GTK_FILL + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 8 + 9 + GTK_FILL + 3 + 3 + + + + + + + + + True + False + Examples + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + + + 1 + + + + + True + False + Formats + + + 1 + False + + + + + True + False + 12 + 12 + + + True + False + 0 + Select keyboards or other input sources + + + False + False + 0 + + + + + True + False + 12 + + + True + False + + + True + True + in + + + True + True + False + + + + + True + True + 0 + + + + + True + False + icons + False + 1 + + + + True + + + True + + + True + + + Add Input Source + + + + + + True + list-add-symbolic + 1 + + + + + + + True + + + Remove Input Source + + + + + True + list-remove-symbolic + 1 + + + + + + + + + + + + True + False + + + True + + + + + + True + + + True + + + True + + + Move Input Source Up + + + + + + True + go-up-symbolic + 1 + + + + + + + True + + + Move Input Source Down + + + + + True + go-down-symbolic + 1 + + + + + + + + + + + + True + False + True + + + True + + + + + + True + + + True + + + True + + + Input Source Settings + + + + + + True + preferences-system-symbolic + 1 + 16 + + + + + + + True + + + Show Keyboard Layout + + + + + + True + input-keyboard-symbolic + 1 + + + + + + + + + + + + False + True + 1 + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 6 + 6 + 6 + + + True + False + 0 + Switch to previous source + + + 0 + 0 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Space + + + + 1 + 0 + 1 + 1 + + + + + True + False + 0 + Switch to next source + + + 0 + 1 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Shift+Space + + + + 1 + 1 + 1 + 1 + + + + + True + True + Shortcut Settings + end + + + 1 + 2 + 1 + 1 + + + + + + + + + True + False + Shortcuts + True + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + 3 + + + + + True + False + Input Sources + + + 3 + False + + + + + True + False + 3 + 2 + 12 + 12 + + + True + False + 0 + 6 + 6 + The login screen, system accounts and new user accounts use the system-wide Region and Language settings. You may change the system settings to match yours. + True + 60 + + + 2 + GTK_FILL + GTK_SHRINK + 3 + 3 + + + + + True + False + 0 + none + + + True + False + 12 + 12 + 3 + 2 + 3 + 3 + + + True + False + 0 + Display language: + + + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + 0 + Input source: + + + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + 0 + True + 18 + + + 1 + 2 + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + Format: + + + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + + + True + False + Your settings + + + + + + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + none + + + True + False + 12 + 12 + 3 + 2 + 3 + 3 + + + True + False + 0 + Display language: + + + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + 0 + Input source: + + + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + 0 + True + 18 + + + 1 + 2 + 1 + 2 + 3 + 3 + GTK_FILL + + + + + True + False + 0 + Format: + + + 2 + 3 + GTK_FILL + 3 + 3 + + + + + True + False + 0 + + + 1 + 2 + 2 + 3 + GTK_FILL + 3 + 3 + + + + + + + True + False + System settings + + + + + + + + 1 + 2 + 1 + 2 + GTK_FILL + 3 + 3 + + + + + Copy Settings... + False + True + True + True + + + 1 + 2 + 2 + 3 + GTK_SHRINK + GTK_SHRINK + 3 + 3 + + + + + + + + 4 + + + + + True + False + System + + + 4 + False + + + + + False + False + 0 + + + + + False + True + 1 + + + + + + + vertical + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/git-sound-fix-port-handling.patch/panels/sound/gvc-mixer-control.c gnome-control-center-3.6.3/.pc/git-sound-fix-port-handling.patch/panels/sound/gvc-mixer-control.c --- gnome-control-center-3.6.3/.pc/git-sound-fix-port-handling.patch/panels/sound/gvc-mixer-control.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/git-sound-fix-port-handling.patch/panels/sound/gvc-mixer-control.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,3358 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006-2008 Lennart Poettering + * Copyright (C) 2008 Sjoerd Simons + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2012 Conor Curran + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "gvc-mixer-control.h" +#include "gvc-mixer-sink.h" +#include "gvc-mixer-source.h" +#include "gvc-mixer-sink-input.h" +#include "gvc-mixer-source-output.h" +#include "gvc-mixer-event-role.h" +#include "gvc-mixer-card.h" +#include "gvc-mixer-card-private.h" +#include "gvc-channel-map-private.h" +#include "gvc-mixer-control-private.h" +#include "gvc-mixer-ui-device.h" + +#define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate)) + +#define RECONNECT_DELAY 5 + +enum { + PROP_0, + PROP_NAME +}; + +struct GvcMixerControlPrivate +{ + pa_glib_mainloop *pa_mainloop; + pa_mainloop_api *pa_api; + pa_context *pa_context; + int n_outstanding; + guint reconnect_id; + char *name; + + gboolean default_sink_is_set; + guint default_sink_id; + char *default_sink_name; + gboolean default_source_is_set; + guint default_source_id; + char *default_source_name; + + gboolean event_sink_input_is_set; + guint event_sink_input_id; + + GHashTable *all_streams; + GHashTable *sinks; /* fixed outputs */ + GHashTable *sources; /* fixed inputs */ + GHashTable *sink_inputs; /* routable output streams */ + GHashTable *source_outputs; /* routable input streams */ + GHashTable *clients; + GHashTable *cards; + + GvcMixerStream *new_default_sink_stream; /* new default sink stream, used in gvc_mixer_control_set_default_sink () */ + GvcMixerStream *new_default_source_stream; /* new default source stream, used in gvc_mixer_control_set_default_source () */ + + GHashTable *ui_outputs; /* UI visible outputs */ + GHashTable *ui_inputs; /* UI visible inputs */ + + /* When we change profile on a device that is not the server default sink, + * it will jump back to the default sink set by the server to prevent the + * audio setup from being 'outputless'. + * + * All well and good but then when we get the new stream created for the + * new profile how do we know that this is the intended default or selected + * device the user wishes to use. */ + guint profile_swapping_device_id; + + GvcMixerControlState state; +}; + +enum { + STATE_CHANGED, + STREAM_ADDED, + STREAM_REMOVED, + CARD_ADDED, + CARD_REMOVED, + DEFAULT_SINK_CHANGED, + DEFAULT_SOURCE_CHANGED, + ACTIVE_OUTPUT_UPDATE, + ACTIVE_INPUT_UPDATE, + OUTPUT_ADDED, + INPUT_ADDED, + OUTPUT_REMOVED, + INPUT_REMOVED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gvc_mixer_control_class_init (GvcMixerControlClass *klass); +static void gvc_mixer_control_init (GvcMixerControl *mixer_control); +static void gvc_mixer_control_finalize (GObject *object); + +G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT) + +pa_context * +gvc_mixer_control_get_pa_context (GvcMixerControl *control) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + return control->priv->pa_context; +} + +/** + * gvc_mixer_control_get_event_sink_input: + * + * @control: + * + * Returns: (transfer none): + */ +GvcMixerStream * +gvc_mixer_control_get_event_sink_input (GvcMixerControl *control) +{ + GvcMixerStream *stream; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + stream = g_hash_table_lookup (control->priv->all_streams, + GUINT_TO_POINTER (control->priv->event_sink_input_id)); + + return stream; +} + +static void +gvc_mixer_control_stream_restore_cb (pa_context *c, + GvcMixerStream *new_stream, + const pa_ext_stream_restore_info *info, + GvcMixerControl *control) +{ + pa_operation *o; + pa_ext_stream_restore_info new_info; + + if (new_stream == NULL) + return; + + new_info.name = info->name; + new_info.channel_map = info->channel_map; + new_info.volume = info->volume; + new_info.mute = info->mute; + + new_info.device = gvc_mixer_stream_get_name (new_stream); + + o = pa_ext_stream_restore_write (control->priv->pa_context, + PA_UPDATE_REPLACE, + &new_info, 1, + TRUE, NULL, NULL); + + if (o == NULL) { + g_warning ("pa_ext_stream_restore_write() failed: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + return; + } + + g_debug ("Changed default device for %s to %s", info->name, new_info.device); + + pa_operation_unref (o); +} + +static void +gvc_mixer_control_stream_restore_sink_cb (pa_context *c, + const pa_ext_stream_restore_info *info, + int eol, + void *userdata) +{ + GvcMixerControl *control = (GvcMixerControl *) userdata; + if (eol || info == NULL || !g_str_has_prefix(info->name, "sink-input-by")) + return; + gvc_mixer_control_stream_restore_cb (c, control->priv->new_default_sink_stream, info, control); +} + +static void +gvc_mixer_control_stream_restore_source_cb (pa_context *c, + const pa_ext_stream_restore_info *info, + int eol, + void *userdata) +{ + GvcMixerControl *control = (GvcMixerControl *) userdata; + if (eol || info == NULL || !g_str_has_prefix(info->name, "source-output-by")) + return; + gvc_mixer_control_stream_restore_cb (c, control->priv->new_default_source_stream, info, control); +} + +/** + * gvc_mixer_control_lookup_device_from_stream: + * @control: + * @stream: + * Returns: (transfer none): a #GvcUIDevice or %NULL + */ +GvcMixerUIDevice * +gvc_mixer_control_lookup_device_from_stream (GvcMixerControl *control, + GvcMixerStream *stream) +{ + GList *devices, *d; + gboolean is_network_stream; + const GList *ports; + GvcMixerUIDevice *ret; + + if (GVC_IS_MIXER_SOURCE (stream)) + devices = g_hash_table_get_values (control->priv->ui_inputs); + else + devices = g_hash_table_get_values (control->priv->ui_outputs); + + ret = NULL; + ports = gvc_mixer_stream_get_ports (stream); + is_network_stream = (ports == NULL); + + for (d = devices; d != NULL; d = d->next) { + GvcMixerUIDevice *device = d->data; + gint stream_id = G_MAXINT; + + g_object_get (G_OBJECT (device), + "stream-id", &stream_id, + NULL); + + if (is_network_stream && + stream_id == gvc_mixer_stream_get_id (stream)) { + g_debug ("lookup device from stream - %s - it is a network_stream ", + gvc_mixer_ui_device_get_description (device)); + ret = device; + break; + } else if (!is_network_stream) { + const GvcMixerStreamPort *port; + port = gvc_mixer_stream_get_port (stream); + + if (stream_id == gvc_mixer_stream_get_id (stream) && + g_strcmp0 (gvc_mixer_ui_device_get_port (device), + port->port) == 0) { + g_debug ("lookup-device-from-stream found device: device description '%s', device port = '%s', device stream id %i AND stream port = '%s' stream id '%u' and stream description '%s'", + gvc_mixer_ui_device_get_description (device), + gvc_mixer_ui_device_get_port (device), + stream_id, + port->port, + gvc_mixer_stream_get_id (stream), + gvc_mixer_stream_get_description (stream)); + ret = device; + break; + } + } + } + + g_debug ("gvc_mixer_control_lookup_device_from_stream - Could not find a device for stream '%s'",gvc_mixer_stream_get_description (stream)); + + g_list_free (devices); + + return ret; +} + +gboolean +gvc_mixer_control_set_default_sink (GvcMixerControl *control, + GvcMixerStream *stream) +{ + pa_operation *o; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); + g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); + + g_debug ("about to set default sink on server"); + o = pa_context_set_default_sink (control->priv->pa_context, + gvc_mixer_stream_get_name (stream), + NULL, + NULL); + if (o == NULL) { + g_warning ("pa_context_set_default_sink() failed: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + return FALSE; + } + + pa_operation_unref (o); + + control->priv->new_default_sink_stream = stream; + g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_sink_stream); + + o = pa_ext_stream_restore_read (control->priv->pa_context, + gvc_mixer_control_stream_restore_sink_cb, + control); + + if (o == NULL) { + g_warning ("pa_ext_stream_restore_read() failed: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + return FALSE; + } + + pa_operation_unref (o); + + return TRUE; +} + +gboolean +gvc_mixer_control_set_default_source (GvcMixerControl *control, + GvcMixerStream *stream) +{ + GvcMixerUIDevice* input; + pa_operation *o; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); + g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); + + o = pa_context_set_default_source (control->priv->pa_context, + gvc_mixer_stream_get_name (stream), + NULL, + NULL); + if (o == NULL) { + g_warning ("pa_context_set_default_source() failed"); + return FALSE; + } + + pa_operation_unref (o); + + control->priv->new_default_source_stream = stream; + g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_source_stream); + + o = pa_ext_stream_restore_read (control->priv->pa_context, + gvc_mixer_control_stream_restore_source_cb, + control); + + if (o == NULL) { + g_warning ("pa_ext_stream_restore_read() failed: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + return FALSE; + } + + pa_operation_unref (o); + + /* source change successful, update the UI. */ + input = gvc_mixer_control_lookup_device_from_stream (control, stream); + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_INPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (input)); + + return TRUE; +} + +/** + * gvc_mixer_control_get_default_sink: + * + * @control: + * + * Returns: (transfer none): + */ +GvcMixerStream * +gvc_mixer_control_get_default_sink (GvcMixerControl *control) +{ + GvcMixerStream *stream; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + if (control->priv->default_sink_is_set) { + stream = g_hash_table_lookup (control->priv->all_streams, + GUINT_TO_POINTER (control->priv->default_sink_id)); + } else { + stream = NULL; + } + + return stream; +} + +/** + * gvc_mixer_control_get_default_source: + * + * @control: + * + * Returns: (transfer none): + */ +GvcMixerStream * +gvc_mixer_control_get_default_source (GvcMixerControl *control) +{ + GvcMixerStream *stream; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + if (control->priv->default_source_is_set) { + stream = g_hash_table_lookup (control->priv->all_streams, + GUINT_TO_POINTER (control->priv->default_source_id)); + } else { + stream = NULL; + } + + return stream; +} + +static gpointer +gvc_mixer_control_lookup_id (GHashTable *hash_table, + guint id) +{ + return g_hash_table_lookup (hash_table, + GUINT_TO_POINTER (id)); +} + +/** + * gvc_mixer_control_lookup_stream_id: + * + * @control: + * @id: + * + * Returns: (transfer none): + */ +GvcMixerStream * +gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, + guint id) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + return gvc_mixer_control_lookup_id (control->priv->all_streams, id); +} + +/** + * gvc_mixer_control_lookup_card_id: + * + * @control: + * @id: + * + * Returns: (transfer none): + */ +GvcMixerCard * +gvc_mixer_control_lookup_card_id (GvcMixerControl *control, + guint id) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + return gvc_mixer_control_lookup_id (control->priv->cards, id); +} + +/** + * gvc_mixer_control_lookup_output_id: + * @control: + * @id: + * Returns: (transfer none): + */ +GvcMixerUIDevice * +gvc_mixer_control_lookup_output_id (GvcMixerControl *control, + guint id) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + return gvc_mixer_control_lookup_id (control->priv->ui_outputs, id); +} + +/** + * gvc_mixer_control_lookup_input_id: + * @control: + * @id: + * Returns: (transfer none): + */ +GvcMixerUIDevice * +gvc_mixer_control_lookup_input_id (GvcMixerControl *control, + guint id) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + return gvc_mixer_control_lookup_id (control->priv->ui_inputs, id); +} + +/** + * gvc_mixer_control_get_stream_from_device: + * @control: + * @device: + * Returns: (transfer none): + */ +GvcMixerStream * +gvc_mixer_control_get_stream_from_device (GvcMixerControl *control, + GvcMixerUIDevice *device) +{ + gint stream_id; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (device), NULL); + + stream_id = gvc_mixer_ui_device_get_stream_id (device); + + if (stream_id == GVC_MIXER_UI_DEVICE_INVALID) { + g_debug ("gvc_mixer_control_get_stream_from_device - device has a null stream"); + return NULL; + } + return gvc_mixer_control_lookup_stream_id (control, stream_id); +} + +/** + * gvc_mixer_control_change_profile_on_selected_device: + * @control: + * @device: + * @profile: Can be null if any profile present on this port is okay + * Returns: This method will attempt to swap the profile on the card of + * the device with given profile name. If successfull it will set the + * preferred profile on that device so as we know the next time the user + * moves to that device it should have this profile active. + */ +gboolean +gvc_mixer_control_change_profile_on_selected_device (GvcMixerControl *control, + GvcMixerUIDevice *device, + const gchar *profile) +{ + const gchar *best_profile; + GvcMixerCardProfile *current_profile; + GvcMixerCard *card; + + g_object_get (G_OBJECT (device), "card", &card, NULL); + current_profile = gvc_mixer_card_get_profile (card); + + if (current_profile) + best_profile = gvc_mixer_ui_device_get_best_profile (device, profile, current_profile->profile); + else + best_profile = profile; + + g_assert (best_profile); + + g_debug ("Selected '%s', moving to profile '%s' on card '%s' on stream id %i", + profile ? profile : "(any)", best_profile, + gvc_mixer_card_get_name (card), + gvc_mixer_ui_device_get_stream_id (device)); + + g_debug ("default sink name = %s and default sink id %u", + control->priv->default_sink_name, + control->priv->default_sink_id); + + control->priv->profile_swapping_device_id = gvc_mixer_ui_device_get_id (device); + + if (gvc_mixer_card_change_profile (card, best_profile)) { + gvc_mixer_ui_device_set_user_preferred_profile (device, best_profile); + return TRUE; + } + return FALSE; +} + +/** + * gvc_mixer_control_change_output: + * @control: + * @output: + * This method is called from the UI when the user selects a previously unselected device. + * - Firstly it queries the stream from the device. + * - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources) + * In the scenario of a NULL stream on the device + * - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device. + * - It then caches this device in control->priv->cached_desired_output_id so that when the update_sink triggered + * from when we attempt to change profile we will know exactly what device to highlight on that stream. + * - It attempts to swap the profile on the card from that device and returns. + * - Next, it handles network or bluetooth streams that only require their stream to be made the default. + * - Next it deals with port changes so if the stream's active port is not the same as the port on the device + * it will attempt to change the port on that stream to be same as the device. If this fails it will return. + * - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active output device. + */ +void +gvc_mixer_control_change_output (GvcMixerControl *control, + GvcMixerUIDevice* output) +{ + GvcMixerStream *stream; + GvcMixerStream *default_stream; + const GvcMixerStreamPort *active_port; + const gchar *output_port; + + g_debug ("control change output"); + + stream = gvc_mixer_control_get_stream_from_device (control, output); + if (stream == NULL) { + gvc_mixer_control_change_profile_on_selected_device (control, + output, NULL); + return; + } + + /* Handle a network sink as a portless or cardless device */ + if (!gvc_mixer_ui_device_has_ports (output)) { + g_debug ("Did we try to move to a software/bluetooth sink ?"); + if (gvc_mixer_control_set_default_sink (control, stream)) { + /* sink change was successful, update the UI.*/ + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_OUTPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (output)); + } + else { + g_warning ("Failed to set default sink with stream from output %s", + gvc_mixer_ui_device_get_description (output)); + } + return; + } + + active_port = gvc_mixer_stream_get_port (stream); + output_port = gvc_mixer_ui_device_get_port (output); + /* First ensure the correct port is active on the sink */ + if (g_strcmp0 (active_port->port, output_port) != 0) { + g_debug ("Port change, switch to = %s", output_port); + if (gvc_mixer_stream_change_port (stream, output_port) == FALSE) { + g_warning ("Could not change port !"); + return; + } + } + + default_stream = gvc_mixer_control_get_default_sink (control); + + /* Finally if we are not on the correct stream, swap over. */ + if (stream != default_stream) { + GvcMixerUIDevice* output; + + g_debug ("Attempting to swap over to stream %s ", + gvc_mixer_stream_get_description (stream)); + if (gvc_mixer_control_set_default_sink (control, stream)) { + output = gvc_mixer_control_lookup_device_from_stream (control, stream); + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_OUTPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (output)); + } else { + /* If the move failed for some reason reset the UI. */ + output = gvc_mixer_control_lookup_device_from_stream (control, default_stream); + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_OUTPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (output)); + } + } +} + + +/** + * gvc_mixer_control_change_input: + * @control: + * @input: + * This method is called from the UI when the user selects a previously unselected device. + * - Firstly it queries the stream from the device. + * - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources) + * In the scenario of a NULL stream on the device + * - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device. + * - It then caches this device in control->priv->cached_desired_input_id so that when the update_source triggered + * from when we attempt to change profile we will know exactly what device to highlight on that stream. + * - It attempts to swap the profile on the card from that device and returns. + * - Next, it handles network or bluetooth streams that only require their stream to be made the default. + * - Next it deals with port changes so if the stream's active port is not the same as the port on the device + * it will attempt to change the port on that stream to be same as the device. If this fails it will return. + * - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active input device. + */ +void +gvc_mixer_control_change_input (GvcMixerControl *control, + GvcMixerUIDevice* input) +{ + GvcMixerStream *stream; + GvcMixerStream *default_stream; + const GvcMixerStreamPort *active_port; + const gchar *input_port; + + stream = gvc_mixer_control_get_stream_from_device (control, input); + if (stream == NULL) { + gvc_mixer_control_change_profile_on_selected_device (control, + input, NULL); + return; + } + + /* Handle a network sink as a portless/cardless device */ + if (!gvc_mixer_ui_device_has_ports (input)) { + g_debug ("Did we try to move to a software/bluetooth source ?"); + if (! gvc_mixer_control_set_default_source (control, stream)) { + g_warning ("Failed to set default source with stream from input %s", + gvc_mixer_ui_device_get_description (input)); + } + return; + } + + active_port = gvc_mixer_stream_get_port (stream); + input_port = gvc_mixer_ui_device_get_port (input); + /* First ensure the correct port is active on the sink */ + if (g_strcmp0 (active_port->port, input_port) != 0) { + g_debug ("Port change, switch to = %s", input_port); + if (gvc_mixer_stream_change_port (stream, input_port) == FALSE) { + g_warning ("Could not change port!"); + return; + } + } + + default_stream = gvc_mixer_control_get_default_source (control); + + /* Finally if we are not on the correct stream, swap over. */ + if (stream != default_stream) { + g_debug ("change-input - attempting to swap over to stream %s", + gvc_mixer_stream_get_description (stream)); + gvc_mixer_control_set_default_source (control, stream); + } +} + + +static void +listify_hash_values_hfunc (gpointer key, + gpointer value, + gpointer user_data) +{ + GSList **list = user_data; + + *list = g_slist_prepend (*list, value); +} + +static int +gvc_name_collate (const char *namea, + const char *nameb) +{ + if (nameb == NULL && namea == NULL) + return 0; + if (nameb == NULL) + return 1; + if (namea == NULL) + return -1; + + return g_utf8_collate (namea, nameb); +} + +static int +gvc_card_collate (GvcMixerCard *a, + GvcMixerCard *b) +{ + const char *namea; + const char *nameb; + + g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0); + g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0); + + namea = gvc_mixer_card_get_name (a); + nameb = gvc_mixer_card_get_name (b); + + return gvc_name_collate (namea, nameb); +} + +/** + * gvc_mixer_control_get_cards: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerCard): + */ +GSList * +gvc_mixer_control_get_cards (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->cards, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_card_collate); +} + +static int +gvc_stream_collate (GvcMixerStream *a, + GvcMixerStream *b) +{ + const char *namea; + const char *nameb; + + g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0); + g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0); + + namea = gvc_mixer_stream_get_name (a); + nameb = gvc_mixer_stream_get_name (b); + + return gvc_name_collate (namea, nameb); +} + +/** + * gvc_mixer_control_get_streams: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerStream): + */ +GSList * +gvc_mixer_control_get_streams (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->all_streams, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); +} + +/** + * gvc_mixer_control_get_sinks: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerSink): + */ +GSList * +gvc_mixer_control_get_sinks (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->sinks, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); +} + +/** + * gvc_mixer_control_get_sources: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerSource): + */ +GSList * +gvc_mixer_control_get_sources (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->sources, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); +} + +/** + * gvc_mixer_control_get_sink_inputs: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerSinkInput): + */ +GSList * +gvc_mixer_control_get_sink_inputs (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->sink_inputs, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); +} + +/** + * gvc_mixer_control_get_source_outputs: + * + * @control: + * + * Returns: (transfer container) (element-type Gvc.MixerSourceOutput): + */ +GSList * +gvc_mixer_control_get_source_outputs (GvcMixerControl *control) +{ + GSList *retval; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); + + retval = NULL; + g_hash_table_foreach (control->priv->source_outputs, + listify_hash_values_hfunc, + &retval); + return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); +} + +static void +dec_outstanding (GvcMixerControl *control) +{ + if (control->priv->n_outstanding <= 0) { + return; + } + + if (--control->priv->n_outstanding <= 0) { + control->priv->state = GVC_STATE_READY; + g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_READY); + } +} + +GvcMixerControlState +gvc_mixer_control_get_state (GvcMixerControl *control) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); + + return control->priv->state; +} + +static void +on_default_source_port_notify (GObject *object, + GParamSpec *pspec, + GvcMixerControl *control) +{ + char *port; + GvcMixerUIDevice *input; + + g_object_get (object, "port", &port, NULL); + input = gvc_mixer_control_lookup_device_from_stream (control, + GVC_MIXER_STREAM (object)); + + g_debug ("on_default_source_port_notify - moved to port '%s' which SHOULD ?? correspond to output '%s'", + port, + gvc_mixer_ui_device_get_description (input)); + + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_INPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (input)); + + g_free (port); +} + + +static void +_set_default_source (GvcMixerControl *control, + GvcMixerStream *stream) +{ + guint new_id; + + if (stream == NULL) { + control->priv->default_source_id = 0; + control->priv->default_source_is_set = FALSE; + g_signal_emit (control, + signals[DEFAULT_SOURCE_CHANGED], + 0, + PA_INVALID_INDEX); + return; + } + + new_id = gvc_mixer_stream_get_id (stream); + + if (control->priv->default_source_id != new_id) { + GvcMixerUIDevice *input; + control->priv->default_source_id = new_id; + control->priv->default_source_is_set = TRUE; + g_signal_emit (control, + signals[DEFAULT_SOURCE_CHANGED], + 0, + new_id); + + if (control->priv->default_source_is_set) { + g_signal_handlers_disconnect_by_func (gvc_mixer_control_get_default_source (control), + on_default_source_port_notify, + control); + } + + g_signal_connect (stream, + "notify::port", + G_CALLBACK (on_default_source_port_notify), + control); + + input = gvc_mixer_control_lookup_device_from_stream (control, stream); + + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_INPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (input)); + } +} + +static void +on_default_sink_port_notify (GObject *object, + GParamSpec *pspec, + GvcMixerControl *control) +{ + char *port; + GvcMixerUIDevice *output; + + g_object_get (object, "port", &port, NULL); + + output = gvc_mixer_control_lookup_device_from_stream (control, + GVC_MIXER_STREAM (object)); + if (output != NULL) { + g_debug ("on_default_sink_port_notify - moved to port %s - which SHOULD correspond to output %s", + port, + gvc_mixer_ui_device_get_description (output)); + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_OUTPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (output)); + } + g_free (port); +} + +static void +_set_default_sink (GvcMixerControl *control, + GvcMixerStream *stream) +{ + guint new_id; + + if (stream == NULL) { + /* Don't tell front-ends about an unset default + * sink if it's already unset */ + if (control->priv->default_sink_is_set == FALSE) + return; + control->priv->default_sink_id = 0; + control->priv->default_sink_is_set = FALSE; + g_signal_emit (control, + signals[DEFAULT_SINK_CHANGED], + 0, + PA_INVALID_INDEX); + return; + } + + new_id = gvc_mixer_stream_get_id (stream); + + if (control->priv->default_sink_id != new_id) { + GvcMixerUIDevice *output; + if (control->priv->default_sink_is_set) { + g_signal_handlers_disconnect_by_func (gvc_mixer_control_get_default_sink (control), + on_default_sink_port_notify, + control); + } + + control->priv->default_sink_id = new_id; + + control->priv->default_sink_is_set = TRUE; + g_signal_emit (control, + signals[DEFAULT_SINK_CHANGED], + 0, + new_id); + + g_signal_connect (stream, + "notify::port", + G_CALLBACK (on_default_sink_port_notify), + control); + + output = gvc_mixer_control_lookup_device_from_stream (control, stream); + + g_debug ("active_sink change"); + + g_signal_emit (G_OBJECT (control), + signals[ACTIVE_OUTPUT_UPDATE], + 0, + gvc_mixer_ui_device_get_id (output)); + } +} + +static gboolean +_stream_has_name (gpointer key, + GvcMixerStream *stream, + const char *name) +{ + const char *t_name; + + t_name = gvc_mixer_stream_get_name (stream); + + if (t_name != NULL + && name != NULL + && strcmp (t_name, name) == 0) { + return TRUE; + } + + return FALSE; +} + +static GvcMixerStream * +find_stream_for_name (GvcMixerControl *control, + const char *name) +{ + GvcMixerStream *stream; + + stream = g_hash_table_find (control->priv->all_streams, + (GHRFunc)_stream_has_name, + (char *)name); + return stream; +} + +static void +update_default_source_from_name (GvcMixerControl *control, + const char *name) +{ + gboolean changed = FALSE; + + if ((control->priv->default_source_name == NULL + && name != NULL) + || (control->priv->default_source_name != NULL + && name == NULL) + || (name != NULL && strcmp (control->priv->default_source_name, name) != 0)) { + changed = TRUE; + } + + if (changed) { + GvcMixerStream *stream; + + g_free (control->priv->default_source_name); + control->priv->default_source_name = g_strdup (name); + + stream = find_stream_for_name (control, name); + _set_default_source (control, stream); + } +} + +static void +update_default_sink_from_name (GvcMixerControl *control, + const char *name) +{ + gboolean changed = FALSE; + + if ((control->priv->default_sink_name == NULL + && name != NULL) + || (control->priv->default_sink_name != NULL + && name == NULL) + || (name != NULL && strcmp (control->priv->default_sink_name, name) != 0)) { + changed = TRUE; + } + + if (changed) { + GvcMixerStream *stream; + g_free (control->priv->default_sink_name); + control->priv->default_sink_name = g_strdup (name); + + stream = find_stream_for_name (control, name); + _set_default_sink (control, stream); + } +} + +static void +update_server (GvcMixerControl *control, + const pa_server_info *info) +{ + if (info->default_source_name != NULL) { + update_default_source_from_name (control, info->default_source_name); + } + if (info->default_sink_name != NULL) { + g_debug ("update server"); + update_default_sink_from_name (control, info->default_sink_name); + } +} + +static void +remove_stream (GvcMixerControl *control, + GvcMixerStream *stream) +{ + guint id; + + g_object_ref (stream); + + id = gvc_mixer_stream_get_id (stream); + + if (id == control->priv->default_sink_id) { + _set_default_sink (control, NULL); + } else if (id == control->priv->default_source_id) { + _set_default_source (control, NULL); + } + + g_hash_table_remove (control->priv->all_streams, + GUINT_TO_POINTER (id)); + g_signal_emit (G_OBJECT (control), + signals[STREAM_REMOVED], + 0, + gvc_mixer_stream_get_id (stream)); + g_object_unref (stream); +} + +static void +add_stream (GvcMixerControl *control, + GvcMixerStream *stream) +{ + g_hash_table_insert (control->priv->all_streams, + GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)), + stream); + g_signal_emit (G_OBJECT (control), + signals[STREAM_ADDED], + 0, + gvc_mixer_stream_get_id (stream)); +} + +/* This method will match individual stream ports against its corresponding device + * It does this by: + * - iterates through our devices and finds the one where the card-id on the device is the same as the card-id on the stream + * and the port-name on the device is the same as the streamport-name. + * This should always find a match and is used exclusively by sync_devices(). + */ +static gboolean +match_stream_with_devices (GvcMixerControl *control, + GvcMixerStreamPort *stream_port, + GvcMixerStream *stream) +{ + GList *devices, *d; + guint stream_card_id; + guint stream_id; + gboolean in_possession = FALSE; + + stream_id = gvc_mixer_stream_get_id (stream); + stream_card_id = gvc_mixer_stream_get_card_index (stream); + + devices = g_hash_table_get_values (GVC_IS_MIXER_SOURCE (stream) ? control->priv->ui_inputs : control->priv->ui_outputs); + + for (d = devices; d != NULL; d = d->next) { + GvcMixerUIDevice *device; + gint device_stream_id; + gchar *device_port_name; + gchar *origin; + gchar *description; + GvcMixerCard *card; + gint card_id; + + device = d->data; + g_object_get (G_OBJECT (device), + "stream-id", &device_stream_id, + "card", &card, + "origin", &origin, + "description", &description, + "port-name", &device_port_name, + NULL); + + card_id = gvc_mixer_card_get_index (card); + + g_debug ("Attempt to match_stream update_with_existing_outputs - Try description : '%s', origin : '%s', device port name : '%s', card : %p, AGAINST stream port: '%s', sink card id %i", + description, + origin, + device_port_name, + card, + stream_port->port, + stream_card_id); + + if (stream_card_id == card_id && + g_strcmp0 (device_port_name, stream_port->port) == 0) { + g_debug ("Match device with stream: We have a match with description: '%s', origin: '%s', cached already with device id %u, so set stream id to %i", + description, + origin, + gvc_mixer_ui_device_get_id (device), + stream_id); + + g_object_set (G_OBJECT (device), + "stream-id", (gint)stream_id, + NULL); + in_possession = TRUE; + } + + g_free (device_port_name); + g_free (origin); + g_free (description); + + if (in_possession == TRUE) + break; + } + + g_list_free (devices); + return in_possession; +} + +/* + * This method attempts to match a sink or source with its relevant UI device. + * GvcMixerStream can represent both a sink or source. + * Using static card port introspection implies that we know beforehand what + * outputs and inputs are available to the user. + * But that does not mean that all of these inputs and outputs are available to be used. + * For instance we might be able to see that there is a HDMI port available but if + * we are on the default analog stereo output profile there is no valid sink for + * that HDMI device. We first need to change profile and when update_sink() is called + * only then can we match the new hdmi sink with its corresponding device. + * + * Firstly it checks to see if the incoming stream has no ports. + * - If a stream has no ports but has a valid card ID (bluetooth), it will attempt + * to match the device with the stream using the card id. + * - If a stream has no ports and no valid card id, it goes ahead and makes a new + * device (software/network devices are only detectable at the sink/source level) + * If the stream has ports it will match each port against the stream using match_stream_with_devices(). + * + * This method should always find a match. + */ +static void +sync_devices (GvcMixerControl *control, + GvcMixerStream* stream) +{ + /* Go through ports to see what outputs can be created. */ + const GList *stream_ports; + const GList *n = NULL; + gboolean is_output = !GVC_IS_MIXER_SOURCE (stream); + gint stream_port_count = 0; + + stream_ports = gvc_mixer_stream_get_ports (stream); + + if (stream_ports == NULL) { + GvcMixerUIDevice *device; + /* Bluetooth, no ports but a valid card */ + if (gvc_mixer_stream_get_card_index (stream) != PA_INVALID_INDEX) { + GList *devices, *d; + gboolean in_possession = FALSE; + + devices = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs); + + for (d = devices; d != NULL; d = d->next) { + GvcMixerCard *card; + gint card_id; + + device = d->data; + + g_object_get (G_OBJECT (device), + "card", &card, + NULL); + card_id = gvc_mixer_card_get_index (card); + g_debug ("sync devices, device description - '%s', device card id - %i, stream description - %s, stream card id - %i", + gvc_mixer_ui_device_get_description (device), + card_id, + gvc_mixer_stream_get_description (stream), + gvc_mixer_stream_get_card_index (stream)); + if (card_id == gvc_mixer_stream_get_card_index (stream)) { + in_possession = TRUE; + break; + } + } + g_list_free (devices); + + if (!in_possession) { + g_warning ("Couldn't match the portless stream (with card) - '%s' is it an input ? -> %i, streams card id -> %i", + gvc_mixer_stream_get_description (stream), + GVC_IS_MIXER_SOURCE (stream), + gvc_mixer_stream_get_card_index (stream)); + return; + } + + g_object_set (G_OBJECT (device), + "stream-id", (gint)gvc_mixer_stream_get_id (stream), + "description", gvc_mixer_stream_get_description (stream), + "origin", "", /*Leave it empty for these special cases*/ + "port-name", NULL, + "port-available", TRUE, + NULL); + } else { /* Network sink/source has no ports and no card. */ + GObject *object; + + object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE, + "stream-id", (gint)gvc_mixer_stream_get_id (stream), + "description", gvc_mixer_stream_get_description (stream), + "origin", "", /* Leave it empty for these special cases */ + "port-name", NULL, + "port-available", TRUE, + NULL); + device = GVC_MIXER_UI_DEVICE (object); + + g_hash_table_insert (is_output ? control->priv->ui_outputs : control->priv->ui_inputs, + GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (device)), + g_object_ref (device)); + + } + g_signal_emit (G_OBJECT (control), + signals[is_output ? OUTPUT_ADDED : INPUT_ADDED], + 0, + gvc_mixer_ui_device_get_id (device)); + + return; + } + + /* Go ahead and make sure to match each port against a previously created device */ + for (n = stream_ports; n != NULL; n = n->next) { + + GvcMixerStreamPort *stream_port; + stream_port = n->data; + stream_port_count ++; + + if (match_stream_with_devices (control, stream_port, stream)) + continue; + + g_warning ("Sync_devices: Failed to match stream id: %u, description: '%s', origin: '%s'", + gvc_mixer_stream_get_id (stream), + stream_port->human_port, + gvc_mixer_stream_get_description (stream)); + } +} + +static void +set_icon_name_from_proplist (GvcMixerStream *stream, + pa_proplist *l, + const char *default_icon_name) +{ + const char *t; + + if ((t = pa_proplist_gets (l, PA_PROP_DEVICE_ICON_NAME))) { + goto finish; + } + + if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) { + goto finish; + } + + if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) { + goto finish; + } + + if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) { + goto finish; + } + + if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { + + if (strcmp (t, "video") == 0 || + strcmp (t, "phone") == 0) { + goto finish; + } + + if (strcmp (t, "music") == 0) { + t = "audio"; + goto finish; + } + + if (strcmp (t, "game") == 0) { + t = "applications-games"; + goto finish; + } + + if (strcmp (t, "event") == 0) { + t = "dialog-information"; + goto finish; + } + } + + t = default_icon_name; + + finish: + gvc_mixer_stream_set_icon_name (stream, t); +} + +/* + * Called when anything changes with a sink. + */ +static void +update_sink (GvcMixerControl *control, + const pa_sink_info *info) +{ + GvcMixerStream *stream; + gboolean is_new; + pa_volume_t max_volume; + GvcChannelMap *map; + char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX]; + + pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map); +#if 1 + g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'", + info->index, + info->name, + info->description, + map_buff); +#endif + + map = NULL; + is_new = FALSE; + stream = g_hash_table_lookup (control->priv->sinks, + GUINT_TO_POINTER (info->index)); + + if (stream == NULL) { + GList *list = NULL; + guint i; + + map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); + stream = gvc_mixer_sink_new (control->priv->pa_context, + info->index, + map); + + for (i = 0; i < info->n_ports; i++) { + GvcMixerStreamPort *port; + + port = g_new0 (GvcMixerStreamPort, 1); + port->port = g_strdup (info->ports[i]->name); + port->human_port = g_strdup (info->ports[i]->description); + port->priority = info->ports[i]->priority; + port->available = info->ports[i]->available != PA_PORT_AVAILABLE_NO; + + list = g_list_prepend (list, port); + } + gvc_mixer_stream_set_ports (stream, list); + + g_object_unref (map); + is_new = TRUE; + + } else if (gvc_mixer_stream_is_running (stream)) { + /* Ignore events if volume changes are outstanding */ + g_debug ("Ignoring event, volume changes are outstanding"); + return; + } + + max_volume = pa_cvolume_max (&info->volume); + gvc_mixer_stream_set_name (stream, info->name); + gvc_mixer_stream_set_card_index (stream, info->card); + gvc_mixer_stream_set_description (stream, info->description); + set_icon_name_from_proplist (stream, info->proplist, "audio-card"); + gvc_mixer_stream_set_sysfs_path (stream, pa_proplist_gets (info->proplist, "sysfs.path")); + gvc_mixer_stream_set_volume (stream, (guint)max_volume); + gvc_mixer_stream_set_is_muted (stream, info->mute); + gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME)); + gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); + + /* Messy I know but to set the port everytime regardless of whether it has changed will cost us a + * port change notify signal which causes the frontend to resync. + * Only update the UI when something has changed. */ + if (info->active_port != NULL) { + if (is_new) + gvc_mixer_stream_set_port (stream, info->active_port->name); + else { + const GvcMixerStreamPort *active_port; + active_port = gvc_mixer_stream_get_port (stream); + if (active_port == NULL || + g_strcmp0 (active_port->port, info->active_port->name) != 0) { + g_debug ("update sink - apparently a port update"); + gvc_mixer_stream_set_port (stream, info->active_port->name); + } + } + } + + if (is_new) { + g_debug ("update sink - is new"); + + g_hash_table_insert (control->priv->sinks, + GUINT_TO_POINTER (info->index), + g_object_ref (stream)); + add_stream (control, stream); + /* Always sink on a new stream to able to assign the right stream id + * to the appropriate outputs (multiple potential outputs per stream). */ + sync_devices (control, stream); + } + + /* + * When we change profile on a device that is not the server default sink, + * it will jump back to the default sink set by the server to prevent the audio setup from being 'outputless'. + * All well and good but then when we get the new stream created for the new profile how do we know + * that this is the intended default or selected device the user wishes to use. + * This is messy but it's the only reliable way that it can be done without ripping the whole thing apart. + */ + if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID) { + GvcMixerUIDevice *dev = NULL; + dev = gvc_mixer_control_lookup_output_id (control, control->priv->profile_swapping_device_id); + if (dev != NULL) { + /* now check to make sure this new stream is the same stream just matched and set on the device object */ + if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)) { + g_debug ("Looks like we profile swapped on a non server default sink"); + gvc_mixer_control_set_default_sink (control, stream); + } + } + control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID; + } + + if (control->priv->default_sink_name != NULL + && info->name != NULL + && strcmp (control->priv->default_sink_name, info->name) == 0) { + _set_default_sink (control, stream); + } + + if (map == NULL) + map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream); + + gvc_channel_map_volume_changed (map, &info->volume, FALSE); +} + +static void +update_source (GvcMixerControl *control, + const pa_source_info *info) +{ + GvcMixerStream *stream; + gboolean is_new; + pa_volume_t max_volume; + +#if 1 + g_debug ("Updating source: index=%u name='%s' description='%s'", + info->index, + info->name, + info->description); +#endif + + /* completely ignore monitors, they're not real sources */ + if (info->monitor_of_sink != PA_INVALID_INDEX) { + return; + } + + is_new = FALSE; + + stream = g_hash_table_lookup (control->priv->sources, + GUINT_TO_POINTER (info->index)); + if (stream == NULL) { + GList *list = NULL; + guint i; + GvcChannelMap *map; + + map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); + stream = gvc_mixer_source_new (control->priv->pa_context, + info->index, + map); + + for (i = 0; i < info->n_ports; i++) { + GvcMixerStreamPort *port; + + port = g_new0 (GvcMixerStreamPort, 1); + port->port = g_strdup (info->ports[i]->name); + port->human_port = g_strdup (info->ports[i]->description); + port->priority = info->ports[i]->priority; + list = g_list_prepend (list, port); + } + gvc_mixer_stream_set_ports (stream, list); + + g_object_unref (map); + is_new = TRUE; + } else if (gvc_mixer_stream_is_running (stream)) { + /* Ignore events if volume changes are outstanding */ + g_debug ("Ignoring event, volume changes are outstanding"); + return; + } + + max_volume = pa_cvolume_max (&info->volume); + + gvc_mixer_stream_set_name (stream, info->name); + gvc_mixer_stream_set_card_index (stream, info->card); + gvc_mixer_stream_set_description (stream, info->description); + set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); + gvc_mixer_stream_set_volume (stream, (guint)max_volume); + gvc_mixer_stream_set_is_muted (stream, info->mute); + gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME)); + gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); + g_debug ("update source"); + + if (info->active_port != NULL) { + if (is_new) + gvc_mixer_stream_set_port (stream, info->active_port->name); + else { + const GvcMixerStreamPort *active_port; + active_port = gvc_mixer_stream_get_port (stream); + if (active_port == NULL || + g_strcmp0 (active_port->port, info->active_port->name) != 0) { + g_debug ("update source - apparently a port update"); + gvc_mixer_stream_set_port (stream, info->active_port->name); + } + } + } + + if (is_new) { + g_hash_table_insert (control->priv->sources, + GUINT_TO_POINTER (info->index), + g_object_ref (stream)); + add_stream (control, stream); + sync_devices (control, stream); + } + + if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID) { + GvcMixerUIDevice *dev = NULL; + + dev = gvc_mixer_control_lookup_input_id (control, control->priv->profile_swapping_device_id); + + if (dev != NULL) { + /* now check to make sure this new stream is the same stream just matched and set on the device object */ + if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)) { + g_debug ("Looks like we profile swapped on a non server default sink"); + gvc_mixer_control_set_default_source (control, stream); + } + } + control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID; + } + if (control->priv->default_source_name != NULL + && info->name != NULL + && strcmp (control->priv->default_source_name, info->name) == 0) { + _set_default_source (control, stream); + } +} + +static void +set_is_event_stream_from_proplist (GvcMixerStream *stream, + pa_proplist *l) +{ + const char *t; + gboolean is_event_stream; + + is_event_stream = FALSE; + + if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { + if (g_str_equal (t, "event")) + is_event_stream = TRUE; + } + + gvc_mixer_stream_set_is_event_stream (stream, is_event_stream); +} + +static void +set_application_id_from_proplist (GvcMixerStream *stream, + pa_proplist *l) +{ + const char *t; + + if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) { + gvc_mixer_stream_set_application_id (stream, t); + } +} + +static void +update_sink_input (GvcMixerControl *control, + const pa_sink_input_info *info) +{ + GvcMixerStream *stream; + gboolean is_new; + pa_volume_t max_volume; + const char *name; + +#if 0 + g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u", + info->index, + info->name, + info->client, + info->sink); +#endif + + is_new = FALSE; + + stream = g_hash_table_lookup (control->priv->sink_inputs, + GUINT_TO_POINTER (info->index)); + if (stream == NULL) { + GvcChannelMap *map; + map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); + stream = gvc_mixer_sink_input_new (control->priv->pa_context, + info->index, + map); + g_object_unref (map); + is_new = TRUE; + } else if (gvc_mixer_stream_is_running (stream)) { + /* Ignore events if volume changes are outstanding */ + g_debug ("Ignoring event, volume changes are outstanding"); + return; + } + + max_volume = pa_cvolume_max (&info->volume); + + name = (const char *)g_hash_table_lookup (control->priv->clients, + GUINT_TO_POINTER (info->client)); + gvc_mixer_stream_set_name (stream, name); + gvc_mixer_stream_set_description (stream, info->name); + + set_application_id_from_proplist (stream, info->proplist); + set_is_event_stream_from_proplist (stream, info->proplist); + set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia"); + gvc_mixer_stream_set_volume (stream, (guint)max_volume); + gvc_mixer_stream_set_is_muted (stream, info->mute); + gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX); + + if (is_new) { + g_hash_table_insert (control->priv->sink_inputs, + GUINT_TO_POINTER (info->index), + g_object_ref (stream)); + add_stream (control, stream); + } +} + +static void +update_source_output (GvcMixerControl *control, + const pa_source_output_info *info) +{ + GvcMixerStream *stream; + gboolean is_new; + const char *name; + +#if 1 + g_debug ("Updating source output: index=%u name='%s' client=%u source=%u", + info->index, + info->name, + info->client, + info->source); +#endif + + is_new = FALSE; + stream = g_hash_table_lookup (control->priv->source_outputs, + GUINT_TO_POINTER (info->index)); + if (stream == NULL) { + GvcChannelMap *map; + map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); + stream = gvc_mixer_source_output_new (control->priv->pa_context, + info->index, + map); + g_object_unref (map); + is_new = TRUE; + } + + name = (const char *)g_hash_table_lookup (control->priv->clients, + GUINT_TO_POINTER (info->client)); + + gvc_mixer_stream_set_name (stream, name); + gvc_mixer_stream_set_description (stream, info->name); + set_application_id_from_proplist (stream, info->proplist); + set_is_event_stream_from_proplist (stream, info->proplist); + set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); + + if (is_new) { + g_hash_table_insert (control->priv->source_outputs, + GUINT_TO_POINTER (info->index), + g_object_ref (stream)); + add_stream (control, stream); + } +} + +static void +update_client (GvcMixerControl *control, + const pa_client_info *info) +{ +#if 1 + g_debug ("Updating client: index=%u name='%s'", + info->index, + info->name); +#endif + g_hash_table_insert (control->priv->clients, + GUINT_TO_POINTER (info->index), + g_strdup (info->name)); +} + +static char * +card_num_streams_to_status (guint sinks, + guint sources) +{ + char *sinks_str; + char *sources_str; + char *ret; + + if (sinks == 0 && sources == 0) { + /* translators: + * The device has been disabled */ + return g_strdup (_("Disabled")); + } + if (sinks == 0) { + sinks_str = NULL; + } else { + /* translators: + * The number of sound outputs on a particular device */ + sinks_str = g_strdup_printf (ngettext ("%u Output", + "%u Outputs", + sinks), + sinks); + } + if (sources == 0) { + sources_str = NULL; + } else { + /* translators: + * The number of sound inputs on a particular device */ + sources_str = g_strdup_printf (ngettext ("%u Input", + "%u Inputs", + sources), + sources); + } + if (sources_str == NULL) + return sinks_str; + if (sinks_str == NULL) + return sources_str; + ret = g_strdup_printf ("%s / %s", sinks_str, sources_str); + g_free (sinks_str); + g_free (sources_str); + return ret; +} + +/** + * A utility method to gather which card profiles are relevant to the port . + */ +static GList * +determine_profiles_for_port (pa_card_port_info *port, + GList* card_profiles) +{ + gint i; + GList *supported_profiles = NULL; + GList *p; + for (i = 0; i < port->n_profiles; i++) { + for (p = card_profiles; p != NULL; p = p->next) { + GvcMixerCardProfile *prof; + prof = p->data; + if (g_strcmp0 (port->profiles[i]->name, prof->profile) == 0) + supported_profiles = g_list_append (supported_profiles, prof); + } + } + g_debug ("%i profiles supported on port %s", + g_list_length (supported_profiles), + port->description); + return g_list_sort (supported_profiles, (GCompareFunc) gvc_mixer_card_profile_compare); +} + +static gboolean +is_card_port_an_output (GvcMixerCardPort* port) +{ + return port->direction == PA_DIRECTION_OUTPUT ? TRUE : FALSE; +} + +/* + * This method will create a ui device for the given port. + */ +static void +create_ui_device_from_port (GvcMixerControl* control, + GvcMixerCardPort* port, + GvcMixerCard* card) +{ + GvcMixerUIDeviceDirection direction; + GObject *object; + GvcMixerUIDevice *uidevice; + gboolean available = port->available != PA_PORT_AVAILABLE_NO; + + direction = (is_card_port_an_output (port) == TRUE) ? UIDeviceOutput : UIDeviceInput; + + object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE, + "type", (uint)direction, + "card", card, + "port-name", port->port, + "description", port->human_port, + "origin", gvc_mixer_card_get_name (card), + "port-available", available, + NULL); + + uidevice = GVC_MIXER_UI_DEVICE (object); + gvc_mixer_ui_device_set_profiles (uidevice, port->profiles); + + g_hash_table_insert (is_card_port_an_output (port) ? control->priv->ui_outputs : control->priv->ui_inputs, + GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (uidevice)), + g_object_ref (uidevice)); + + + if (available) { + g_signal_emit (G_OBJECT (control), + signals[is_card_port_an_output (port) ? OUTPUT_ADDED : INPUT_ADDED], + 0, + gvc_mixer_ui_device_get_id (uidevice)); + } + + g_debug ("create_ui_device_from_port, direction %u, description '%s', origin '%s', port available %i", + direction, + port->human_port, + gvc_mixer_card_get_name (card), + available); +} + +/* + * This method will match up GvcMixerCardPorts with existing devices. + * A match is achieved if the device's card-id and the port's card-id are the same + * && the device's port-name and the card-port's port member are the same. + * A signal is then sent adding or removing that device from the UI depending on the availability of the port. + */ +static void +match_card_port_with_existing_device (GvcMixerControl *control, + GvcMixerCardPort *card_port, + GvcMixerCard *card, + gboolean available) +{ + GList *d; + GList *devices; + GvcMixerUIDevice *device; + gboolean is_output = is_card_port_an_output (card_port); + + devices = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs); + + for (d = devices; d != NULL; d = d->next) { + GvcMixerCard *device_card; + gchar *device_port_name; + + device = d->data; + g_object_get (G_OBJECT (device), + "card", &device_card, + "port-name", &device_port_name, + NULL); + + if (g_strcmp0 (card_port->port, device_port_name) == 0 && + device_card == card) { + g_debug ("Found the relevant device %s, update its port availability flag to %i, is_output %i", + device_port_name, + available, + is_output); + g_object_set (G_OBJECT (device), + "port-available", available, NULL); + g_signal_emit (G_OBJECT (control), + is_output ? signals[available ? OUTPUT_ADDED : OUTPUT_REMOVED] : signals[available ? INPUT_ADDED : INPUT_REMOVED], + 0, + gvc_mixer_ui_device_get_id (device)); + } + g_free (device_port_name); + } + + g_list_free (devices); +} + +static void +create_ui_device_from_card (GvcMixerControl *control, + GvcMixerCard *card) +{ + GObject *object; + GvcMixerUIDevice *in; + GvcMixerUIDevice *out; + const GList *profiles; + + /* For now just create two devices and presume this device is multi directional + * Ensure to remove both on card removal (available to false by default) */ + profiles = gvc_mixer_card_get_profiles (card); + + g_debug ("Portless card just registered - %i", gvc_mixer_card_get_index (card)); + + object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE, + "type", UIDeviceInput, + "description", gvc_mixer_card_get_name (card), + "origin", "", /* Leave it empty for these special cases */ + "port-name", NULL, + "port-available", FALSE, + "card", card, + NULL); + in = GVC_MIXER_UI_DEVICE (object); + gvc_mixer_ui_device_set_profiles (in, profiles); + + g_hash_table_insert (control->priv->ui_inputs, + GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (in)), + g_object_ref (in)); + object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE, + "type", UIDeviceOutput, + "description", gvc_mixer_card_get_name (card), + "origin", "", /* Leave it empty for these special cases */ + "port-name", NULL, + "port-available", FALSE, + "card", card, + NULL); + out = GVC_MIXER_UI_DEVICE (object); + gvc_mixer_ui_device_set_profiles (out, profiles); + + g_hash_table_insert (control->priv->ui_outputs, + GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (out)), + g_object_ref (out)); +} + +/* + * At this point we can determine all devices available to us (besides network 'ports') + * This is done by the following: + * + * - gvc_mixer_card and gvc_mixer_card_ports are created and relevant setters are called. + * - First it checks to see if it's a portless card. Bluetooth devices are portless AFAIHS. + * If so it creates two devices, an input and an output. + * - If it's a 'normal' card with ports it will create a new ui-device or + * synchronise port availability with the existing device cached for that port on this card. */ + +static void +update_card (GvcMixerControl *control, + const pa_card_info *info) +{ + const GList *card_ports = NULL; + const GList *m = NULL; + GvcMixerCard *card; + gboolean is_new = FALSE; +#if 1 + guint i; + const char *key; + void *state; + + g_debug ("Udpating card %s (index: %u driver: %s):", + info->name, info->index, info->driver); + + for (i = 0; i < info->n_profiles; i++) { + struct pa_card_profile_info pi = info->profiles[i]; + gboolean is_default; + + is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0); + g_debug ("\tProfile '%s': %d sources %d sinks%s", + pi.name, pi.n_sources, pi.n_sinks, + is_default ? " (Current)" : ""); + } + state = NULL; + key = pa_proplist_iterate (info->proplist, &state); + while (key != NULL) { + g_debug ("\tProperty: '%s' = '%s'", + key, pa_proplist_gets (info->proplist, key)); + key = pa_proplist_iterate (info->proplist, &state); + } +#endif + card = g_hash_table_lookup (control->priv->cards, + GUINT_TO_POINTER (info->index)); + if (card == NULL) { + GList *profile_list = NULL; + GList *port_list = NULL; + + for (i = 0; i < info->n_profiles; i++) { + GvcMixerCardProfile *profile; + struct pa_card_profile_info pi = info->profiles[i]; + + profile = g_new0 (GvcMixerCardProfile, 1); + profile->profile = g_strdup (pi.name); + profile->human_profile = g_strdup (pi.description); + profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources); + profile->n_sinks = pi.n_sinks; + profile->n_sources = pi.n_sources; + profile->priority = pi.priority; + profile_list = g_list_prepend (profile_list, profile); + } + card = gvc_mixer_card_new (control->priv->pa_context, + info->index); + gvc_mixer_card_set_profiles (card, profile_list); + + for (i = 0; i < info->n_ports; i++) { + GvcMixerCardPort *port; + port = g_new0 (GvcMixerCardPort, 1); + port->port = g_strdup (info->ports[i]->name); + port->human_port = g_strdup (info->ports[i]->description); + port->priority = info->ports[i]->priority; + port->available = info->ports[i]->available; + port->direction = info->ports[i]->direction; + port->profiles = determine_profiles_for_port (info->ports[i], profile_list); + port_list = g_list_prepend (port_list, port); + } + gvc_mixer_card_set_ports (card, port_list); + is_new = TRUE; + } + + gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description")); + gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name")); + gvc_mixer_card_set_profile (card, info->active_profile->name); + + if (is_new) { + g_hash_table_insert (control->priv->cards, + GUINT_TO_POINTER (info->index), + g_object_ref (card)); + } + + card_ports = gvc_mixer_card_get_ports (card); + + if (card_ports == NULL && is_new) { + g_debug ("Portless card just registered - %s", gvc_mixer_card_get_name (card)); + create_ui_device_from_card (control, card); + } + + for (m = card_ports; m != NULL; m = m->next) { + GvcMixerCardPort *card_port; + card_port = m->data; + if (is_new) + create_ui_device_from_port (control, card_port, card); + else { + for (i = 0; i < info->n_ports; i++) { + if (g_strcmp0 (card_port->port, info->ports[i]->name) == 0) { + if (card_port->available != info->ports[i]->available) { + card_port->available = info->ports[i]->available; + g_debug ("sync port availability on card %i, card port name '%s', new available value %i", + gvc_mixer_card_get_index (card), + card_port->port, + card_port->available); + match_card_port_with_existing_device (control, + card_port, + card, + card_port->available != PA_PORT_AVAILABLE_NO); + } + } + } + } + } + g_signal_emit (G_OBJECT (control), + signals[CARD_ADDED], + 0, + info->index); +} + +static void +_pa_context_get_sink_info_cb (pa_context *context, + const pa_sink_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) { + return; + } + + g_warning ("Sink callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_sink (control, i); +} + +static void +_pa_context_get_source_info_cb (pa_context *context, + const pa_source_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) { + return; + } + + g_warning ("Source callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_source (control, i); +} + +static void +_pa_context_get_sink_input_info_cb (pa_context *context, + const pa_sink_input_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) { + return; + } + + g_warning ("Sink input callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_sink_input (control, i); +} + +static void +_pa_context_get_source_output_info_cb (pa_context *context, + const pa_source_output_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) { + return; + } + + g_warning ("Source output callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_source_output (control, i); +} + +static void +_pa_context_get_client_info_cb (pa_context *context, + const pa_client_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) { + return; + } + + g_warning ("Client callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_client (control, i); +} + +static void +_pa_context_get_card_info_by_index_cb (pa_context *context, + const pa_card_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + if (pa_context_errno (context) == PA_ERR_NOENTITY) + return; + + g_warning ("Card callback failure"); + return; + } + + if (eol > 0) { + dec_outstanding (control); + return; + } + + update_card (control, i); +} + +static void +_pa_context_get_server_info_cb (pa_context *context, + const pa_server_info *i, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (i == NULL) { + g_warning ("Server info callback failure"); + return; + } + g_debug ("get server info"); + update_server (control, i); + dec_outstanding (control); +} + +static void +remove_event_role_stream (GvcMixerControl *control) +{ + g_debug ("Removing event role"); +} + +static void +update_event_role_stream (GvcMixerControl *control, + const pa_ext_stream_restore_info *info) +{ + GvcMixerStream *stream; + gboolean is_new; + pa_volume_t max_volume; + + if (strcmp (info->name, "sink-input-by-media-role:event") != 0) { + return; + } + +#if 0 + g_debug ("Updating event role: name='%s' device='%s'", + info->name, + info->device); +#endif + + is_new = FALSE; + + if (!control->priv->event_sink_input_is_set) { + pa_channel_map pa_map; + GvcChannelMap *map; + + pa_map.channels = 1; + pa_map.map[0] = PA_CHANNEL_POSITION_MONO; + map = gvc_channel_map_new_from_pa_channel_map (&pa_map); + + stream = gvc_mixer_event_role_new (control->priv->pa_context, + info->device, + map); + control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream); + control->priv->event_sink_input_is_set = TRUE; + + is_new = TRUE; + } else { + stream = g_hash_table_lookup (control->priv->all_streams, + GUINT_TO_POINTER (control->priv->event_sink_input_id)); + } + + max_volume = pa_cvolume_max (&info->volume); + + gvc_mixer_stream_set_name (stream, _("System Sounds")); + gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control"); + gvc_mixer_stream_set_volume (stream, (guint)max_volume); + gvc_mixer_stream_set_is_muted (stream, info->mute); + + if (is_new) { + add_stream (control, stream); + } +} + +static void +_pa_ext_stream_restore_read_cb (pa_context *context, + const pa_ext_stream_restore_info *i, + int eol, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + if (eol < 0) { + g_debug ("Failed to initialized stream_restore extension: %s", + pa_strerror (pa_context_errno (context))); + remove_event_role_stream (control); + return; + } + + if (eol > 0) { + dec_outstanding (control); + /* If we don't have an event stream to restore, then + * set one up with a default 100% volume */ + if (!control->priv->event_sink_input_is_set) { + pa_ext_stream_restore_info info; + + memset (&info, 0, sizeof(info)); + info.name = "sink-input-by-media-role:event"; + info.volume.channels = 1; + info.volume.values[0] = PA_VOLUME_NORM; + update_event_role_stream (control, &info); + } + return; + } + + update_event_role_stream (control, i); +} + +static void +_pa_ext_stream_restore_subscribe_cb (pa_context *context, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + pa_operation *o; + + o = pa_ext_stream_restore_read (context, + _pa_ext_stream_restore_read_cb, + control); + if (o == NULL) { + g_warning ("pa_ext_stream_restore_read() failed"); + return; + } + + pa_operation_unref (o); +} + +static void +req_update_server_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + o = pa_context_get_server_info (control->priv->pa_context, + _pa_context_get_server_info_cb, + control); + if (o == NULL) { + g_warning ("pa_context_get_server_info() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_client_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_client_info_list (control->priv->pa_context, + _pa_context_get_client_info_cb, + control); + } else { + o = pa_context_get_client_info (control->priv->pa_context, + index, + _pa_context_get_client_info_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_client_info_list() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_card (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_card_info_list (control->priv->pa_context, + _pa_context_get_card_info_by_index_cb, + control); + } else { + o = pa_context_get_card_info_by_index (control->priv->pa_context, + index, + _pa_context_get_card_info_by_index_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_get_card_info_by_index() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_sink_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_sink_info_list (control->priv->pa_context, + _pa_context_get_sink_info_cb, + control); + } else { + o = pa_context_get_sink_info_by_index (control->priv->pa_context, + index, + _pa_context_get_sink_info_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_get_sink_info_list() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_source_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_source_info_list (control->priv->pa_context, + _pa_context_get_source_info_cb, + control); + } else { + o = pa_context_get_source_info_by_index(control->priv->pa_context, + index, + _pa_context_get_source_info_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_get_source_info_list() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_sink_input_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_sink_input_info_list (control->priv->pa_context, + _pa_context_get_sink_input_info_cb, + control); + } else { + o = pa_context_get_sink_input_info (control->priv->pa_context, + index, + _pa_context_get_sink_input_info_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_get_sink_input_info_list() failed"); + return; + } + pa_operation_unref (o); +} + +static void +req_update_source_output_info (GvcMixerControl *control, + int index) +{ + pa_operation *o; + + if (index < 0) { + o = pa_context_get_source_output_info_list (control->priv->pa_context, + _pa_context_get_source_output_info_cb, + control); + } else { + o = pa_context_get_source_output_info (control->priv->pa_context, + index, + _pa_context_get_source_output_info_cb, + control); + } + + if (o == NULL) { + g_warning ("pa_context_get_source_output_info_list() failed"); + return; + } + pa_operation_unref (o); +} + +static void +remove_client (GvcMixerControl *control, + guint index) +{ + g_hash_table_remove (control->priv->clients, + GUINT_TO_POINTER (index)); +} + +static void +remove_card (GvcMixerControl *control, + guint index) +{ + + GList *devices, *d; + + devices = g_list_concat (g_hash_table_get_values (control->priv->ui_inputs), + g_hash_table_get_values (control->priv->ui_outputs)); + + for (d = devices; d != NULL; d = d->next) { + GvcMixerCard *card; + GvcMixerUIDevice *device = d->data; + + g_object_get (G_OBJECT (device), "card", &card, NULL); + + if (gvc_mixer_card_get_index (card) == index) { + g_signal_emit (G_OBJECT (control), + signals[gvc_mixer_ui_device_is_output (device) ? OUTPUT_REMOVED : INPUT_REMOVED], + 0, + gvc_mixer_ui_device_get_id (device)); + g_debug ("Card removal remove device %s", + gvc_mixer_ui_device_get_description (device)); + g_hash_table_remove (gvc_mixer_ui_device_is_output (device) ? control->priv->ui_outputs : control->priv->ui_inputs, + GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (device))); + } + } + + g_list_free (devices); + + g_hash_table_remove (control->priv->cards, + GUINT_TO_POINTER (index)); + + g_signal_emit (G_OBJECT (control), + signals[CARD_REMOVED], + 0, + index); +} + +static void +remove_sink (GvcMixerControl *control, + guint index) +{ + GvcMixerStream *stream; + GvcMixerUIDevice *device; + + g_debug ("Removing sink: index=%u", index); + + stream = g_hash_table_lookup (control->priv->sinks, + GUINT_TO_POINTER (index)); + if (stream == NULL) + return; + + device = gvc_mixer_control_lookup_device_from_stream (control, stream); + + if (device != NULL) { + gvc_mixer_ui_device_invalidate_stream (device); + if (!gvc_mixer_ui_device_has_ports (device)) { + g_signal_emit (G_OBJECT (control), + signals[OUTPUT_REMOVED], + 0, + gvc_mixer_ui_device_get_id (device)); + } else { + GList *devices, *d; + + devices = g_hash_table_get_values (control->priv->ui_outputs); + + for (d = devices; d != NULL; d = d->next) { + gint stream_id = GVC_MIXER_UI_DEVICE_INVALID; + device = d->data; + g_object_get (G_OBJECT (device), + "stream-id", &stream_id, + NULL); + if (stream_id == gvc_mixer_stream_get_id (stream)) + gvc_mixer_ui_device_invalidate_stream (device); + } + + g_list_free (devices); + } + } + + g_hash_table_remove (control->priv->sinks, + GUINT_TO_POINTER (index)); + + remove_stream (control, stream); +} + +static void +remove_source (GvcMixerControl *control, + guint index) +{ + GvcMixerStream *stream; + GvcMixerUIDevice *device; + + g_debug ("Removing source: index=%u", index); + + stream = g_hash_table_lookup (control->priv->sources, + GUINT_TO_POINTER (index)); + if (stream == NULL) + return; + + device = gvc_mixer_control_lookup_device_from_stream (control, stream); + + if (device != NULL) { + gvc_mixer_ui_device_invalidate_stream (device); + if (!gvc_mixer_ui_device_has_ports (device)) { + g_signal_emit (G_OBJECT (control), + signals[INPUT_REMOVED], + 0, + gvc_mixer_ui_device_get_id (device)); + } else { + GList *devices, *d; + + devices = g_hash_table_get_values (control->priv->ui_inputs); + + for (d = devices; d != NULL; d = d->next) { + gint stream_id = GVC_MIXER_UI_DEVICE_INVALID; + device = d->data; + g_object_get (G_OBJECT (device), + "stream-id", &stream_id, + NULL); + if (stream_id == gvc_mixer_stream_get_id (stream)) + gvc_mixer_ui_device_invalidate_stream (device); + } + + g_list_free (devices); + } + } + + g_hash_table_remove (control->priv->sources, + GUINT_TO_POINTER (index)); + + remove_stream (control, stream); +} + +static void +remove_sink_input (GvcMixerControl *control, + guint index) +{ + GvcMixerStream *stream; + + g_debug ("Removing sink input: index=%u", index); + + stream = g_hash_table_lookup (control->priv->sink_inputs, + GUINT_TO_POINTER (index)); + if (stream == NULL) { + return; + } + g_hash_table_remove (control->priv->sink_inputs, + GUINT_TO_POINTER (index)); + + remove_stream (control, stream); +} + +static void +remove_source_output (GvcMixerControl *control, + guint index) +{ + GvcMixerStream *stream; + + g_debug ("Removing source output: index=%u", index); + + stream = g_hash_table_lookup (control->priv->source_outputs, + GUINT_TO_POINTER (index)); + if (stream == NULL) { + return; + } + g_hash_table_remove (control->priv->source_outputs, + GUINT_TO_POINTER (index)); + + remove_stream (control, stream); +} + +static void +_pa_context_subscribe_cb (pa_context *context, + pa_subscription_event_type_t t, + uint32_t index, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_sink (control, index); + } else { + req_update_sink_info (control, index); + } + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_source (control, index); + } else { + req_update_source_info (control, index); + } + break; + + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_sink_input (control, index); + } else { + req_update_sink_input_info (control, index); + } + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_source_output (control, index); + } else { + req_update_source_output_info (control, index); + } + break; + + case PA_SUBSCRIPTION_EVENT_CLIENT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_client (control, index); + } else { + req_update_client_info (control, index); + } + break; + + case PA_SUBSCRIPTION_EVENT_SERVER: + req_update_server_info (control, index); + break; + + case PA_SUBSCRIPTION_EVENT_CARD: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + remove_card (control, index); + } else { + req_update_card (control, index); + } + break; + } +} + +static void +gvc_mixer_control_ready (GvcMixerControl *control) +{ + pa_operation *o; + + pa_context_set_subscribe_callback (control->priv->pa_context, + _pa_context_subscribe_cb, + control); + o = pa_context_subscribe (control->priv->pa_context, + (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK| + PA_SUBSCRIPTION_MASK_SOURCE| + PA_SUBSCRIPTION_MASK_SINK_INPUT| + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| + PA_SUBSCRIPTION_MASK_CLIENT| + PA_SUBSCRIPTION_MASK_SERVER| + PA_SUBSCRIPTION_MASK_CARD), + NULL, + NULL); + + if (o == NULL) { + g_warning ("pa_context_subscribe() failed"); + return; + } + pa_operation_unref (o); + + req_update_server_info (control, -1); + req_update_card (control, -1); + req_update_client_info (control, -1); + req_update_sink_info (control, -1); + req_update_source_info (control, -1); + req_update_sink_input_info (control, -1); + req_update_source_output_info (control, -1); + + + control->priv->n_outstanding = 6; + + /* This call is not always supported */ + o = pa_ext_stream_restore_read (control->priv->pa_context, + _pa_ext_stream_restore_read_cb, + control); + if (o != NULL) { + pa_operation_unref (o); + control->priv->n_outstanding++; + + pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context, + _pa_ext_stream_restore_subscribe_cb, + control); + + o = pa_ext_stream_restore_subscribe (control->priv->pa_context, + 1, + NULL, + NULL); + if (o != NULL) { + pa_operation_unref (o); + } + + } else { + g_debug ("Failed to initialized stream_restore extension: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + } +} + +static void +gvc_mixer_new_pa_context (GvcMixerControl *self) +{ + pa_proplist *proplist; + + g_return_if_fail (self); + g_return_if_fail (!self->priv->pa_context); + + proplist = pa_proplist_new (); + pa_proplist_sets (proplist, + PA_PROP_APPLICATION_NAME, + self->priv->name); + pa_proplist_sets (proplist, + PA_PROP_APPLICATION_ID, + "org.gnome.VolumeControl"); + pa_proplist_sets (proplist, + PA_PROP_APPLICATION_ICON_NAME, + "multimedia-volume-control"); + pa_proplist_sets (proplist, + PA_PROP_APPLICATION_VERSION, + PACKAGE_VERSION); + + self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist); + + pa_proplist_free (proplist); + g_assert (self->priv->pa_context); +} + +static void +remove_all_streams (GvcMixerControl *control, GHashTable *hash_table) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, hash_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + remove_stream (control, value); + g_hash_table_iter_remove (&iter); + } +} + +static gboolean +idle_reconnect (gpointer data) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (data); + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail (control, FALSE); + + if (control->priv->pa_context) { + pa_context_unref (control->priv->pa_context); + control->priv->pa_context = NULL; + gvc_mixer_new_pa_context (control); + } + + remove_all_streams (control, control->priv->sinks); + remove_all_streams (control, control->priv->sources); + remove_all_streams (control, control->priv->sink_inputs); + remove_all_streams (control, control->priv->source_outputs); + + g_hash_table_iter_init (&iter, control->priv->clients); + while (g_hash_table_iter_next (&iter, &key, &value)) + g_hash_table_iter_remove (&iter); + + gvc_mixer_control_open (control); /* cannot fail */ + + control->priv->reconnect_id = 0; + return FALSE; +} + +static void +_pa_context_state_cb (pa_context *context, + void *userdata) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); + + switch (pa_context_get_state (context)) { + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + gvc_mixer_control_ready (control); + break; + + case PA_CONTEXT_FAILED: + control->priv->state = GVC_STATE_FAILED; + g_signal_emit (control, signals[STATE_CHANGED], 0, GVC_STATE_FAILED); + if (control->priv->reconnect_id == 0) + control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control); + break; + + case PA_CONTEXT_TERMINATED: + default: + /* FIXME: */ + break; + } +} + +gboolean +gvc_mixer_control_open (GvcMixerControl *control) +{ + int res; + + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); + g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); + g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE); + + pa_context_set_state_callback (control->priv->pa_context, + _pa_context_state_cb, + control); + + control->priv->state = GVC_STATE_CONNECTING; + g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CONNECTING); + res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL); + if (res < 0) { + g_warning ("Failed to connect context: %s", + pa_strerror (pa_context_errno (control->priv->pa_context))); + } + + return res; +} + +gboolean +gvc_mixer_control_close (GvcMixerControl *control) +{ + g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); + g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); + + pa_context_disconnect (control->priv->pa_context); + + control->priv->state = GVC_STATE_CLOSED; + g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CLOSED); + return TRUE; +} + +static void +gvc_mixer_control_dispose (GObject *object) +{ + GvcMixerControl *control = GVC_MIXER_CONTROL (object); + + if (control->priv->reconnect_id != 0) { + g_source_remove (control->priv->reconnect_id); + control->priv->reconnect_id = 0; + } + + if (control->priv->pa_context != NULL) { + pa_context_unref (control->priv->pa_context); + control->priv->pa_context = NULL; + } + + if (control->priv->default_source_name != NULL) { + g_free (control->priv->default_source_name); + control->priv->default_source_name = NULL; + } + if (control->priv->default_sink_name != NULL) { + g_free (control->priv->default_sink_name); + control->priv->default_sink_name = NULL; + } + + if (control->priv->pa_mainloop != NULL) { + pa_glib_mainloop_free (control->priv->pa_mainloop); + control->priv->pa_mainloop = NULL; + } + + if (control->priv->all_streams != NULL) { + g_hash_table_destroy (control->priv->all_streams); + control->priv->all_streams = NULL; + } + + if (control->priv->sinks != NULL) { + g_hash_table_destroy (control->priv->sinks); + control->priv->sinks = NULL; + } + if (control->priv->sources != NULL) { + g_hash_table_destroy (control->priv->sources); + control->priv->sources = NULL; + } + if (control->priv->sink_inputs != NULL) { + g_hash_table_destroy (control->priv->sink_inputs); + control->priv->sink_inputs = NULL; + } + if (control->priv->source_outputs != NULL) { + g_hash_table_destroy (control->priv->source_outputs); + control->priv->source_outputs = NULL; + } + if (control->priv->clients != NULL) { + g_hash_table_destroy (control->priv->clients); + control->priv->clients = NULL; + } + if (control->priv->cards != NULL) { + g_hash_table_destroy (control->priv->cards); + control->priv->cards = NULL; + } + if (control->priv->ui_outputs != NULL) { + g_hash_table_destroy (control->priv->ui_outputs); + control->priv->ui_outputs = NULL; + } + if (control->priv->ui_inputs != NULL) { + g_hash_table_destroy (control->priv->ui_inputs); + control->priv->ui_inputs = NULL; + } + + G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object); +} + +static void +gvc_mixer_control_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GvcMixerControl *self = GVC_MIXER_CONTROL (object); + + switch (prop_id) { + case PROP_NAME: + g_free (self->priv->name); + self->priv->name = g_value_dup_string (value); + g_object_notify (G_OBJECT (self), "name"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gvc_mixer_control_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GvcMixerControl *self = GVC_MIXER_CONTROL (object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, self->priv->name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static GObject * +gvc_mixer_control_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + GvcMixerControl *self; + + object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params); + + self = GVC_MIXER_CONTROL (object); + + gvc_mixer_new_pa_context (self); + self->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID; + + return object; +} + +static void +gvc_mixer_control_class_init (GvcMixerControlClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = gvc_mixer_control_constructor; + object_class->dispose = gvc_mixer_control_dispose; + object_class->finalize = gvc_mixer_control_finalize; + object_class->set_property = gvc_mixer_control_set_property; + object_class->get_property = gvc_mixer_control_get_property; + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "Name", + "Name to display for this mixer control", + NULL, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + + signals [STATE_CHANGED] = + g_signal_new ("state-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, state_changed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [STREAM_ADDED] = + g_signal_new ("stream-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, stream_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [STREAM_REMOVED] = + g_signal_new ("stream-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [CARD_ADDED] = + g_signal_new ("card-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, card_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [CARD_REMOVED] = + g_signal_new ("card-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, card_removed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [DEFAULT_SINK_CHANGED] = + g_signal_new ("default-sink-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [DEFAULT_SOURCE_CHANGED] = + g_signal_new ("default-source-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [ACTIVE_OUTPUT_UPDATE] = + g_signal_new ("active-output-update", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, active_output_update), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [ACTIVE_INPUT_UPDATE] = + g_signal_new ("active-input-update", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, active_input_update), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [OUTPUT_ADDED] = + g_signal_new ("output-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, output_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [INPUT_ADDED] = + g_signal_new ("input-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, input_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [OUTPUT_REMOVED] = + g_signal_new ("output-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, output_removed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [INPUT_REMOVED] = + g_signal_new ("input-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GvcMixerControlClass, input_removed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate)); +} + + +static void +gvc_mixer_control_init (GvcMixerControl *control) +{ + control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control); + + control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ()); + g_assert (control->priv->pa_mainloop); + + control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop); + g_assert (control->priv->pa_api); + + control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->ui_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + control->priv->ui_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); + + control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free); + + control->priv->state = GVC_STATE_CLOSED; +} + +static void +gvc_mixer_control_finalize (GObject *object) +{ + GvcMixerControl *mixer_control; + + g_return_if_fail (object != NULL); + g_return_if_fail (GVC_IS_MIXER_CONTROL (object)); + + mixer_control = GVC_MIXER_CONTROL (object); + g_free (mixer_control->priv->name); + mixer_control->priv->name = NULL; + + g_return_if_fail (mixer_control->priv != NULL); + G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object); +} + +GvcMixerControl * +gvc_mixer_control_new (const char *name) +{ + GObject *control; + control = g_object_new (GVC_TYPE_MIXER_CONTROL, + "name", name, + NULL); + return GVC_MIXER_CONTROL (control); +} + +gdouble +gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control) +{ + return (gdouble) PA_VOLUME_NORM; +} + +gdouble +gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control) +{ + return (gdouble) PA_VOLUME_UI_MAX; +} diff -Nru gnome-control-center-3.6.3/.pc/more-power-suspend-options.patch/panels/power/power.ui gnome-control-center-3.6.3/.pc/more-power-suspend-options.patch/panels/power/power.ui --- gnome-control-center-3.6.3/.pc/more-power-suspend-options.patch/panels/power/power.ui 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/more-power-suspend-options.patch/panels/power/power.ui 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + Hibernate + 3 + True + + + Power off + 2 + True + + + + + + + + + + + + + 5 minutes + 300 + + + 10 minutes + 600 + + + 30 minutes + 1800 + + + 1 hour + 3600 + + + Don't suspend + 0 + + + + + + + + + + + + + + + Suspend + 1 + True + + + Do nothing + 5 + True + + + + + + + + + + + + + When battery is present + present + + + When battery is charging/in use + charge + + + Never + never + + + + + False + False + + + True + False + 12 + 3 + + + True + False + 53 + 60 + 24 + vertical + 6 + 12 + + + True + False + On battery power + center + + + + + + 1 + 0 + + + + + True + False + When plugged in + center + + + + + + 2 + 0 + + + + + True + False + end + Suspend when inactive for + + + 0 + 1 + + + + + True + False + liststore_time + True + + + + + + + 1 + 1 + + + + + 150 + True + False + liststore_time + True + + + + + + + 2 + 1 + + + + + True + False + end + When power is _critically low + True + combobox_critical + + + 0 + 2 + + + + + True + False + liststore_critical + + + 1 + 2 + + + + + True + False + end + When the lid is closed + + + 0 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 1 + 3 + + + + + True + False + liststore_lid + True + + + + + + + 2 + 3 + + + + + True + False + + + 0 + 4 + 4 + 1 + + + + + True + False + end + Show battery status in the _menu bar + True + + + 0 + 5 + + + + + True + False + liststore_indicator + True + + + + + + 1 + 5 + 2 + 1 + + + + + False + False + 0 + + + + + True + False + 53 + 60 + vertical + 3 + + + True + False + 3 + + + True + False + dialog-warning-symbolic + + + False + True + 0 + + + + + True + False + 0 + 55 minutes until fully charged + + + True + True + 1 + + + + + True + False + 3 + + + True + False + 1 + gtk-info + + + False + True + 0 + + + + + True + False + 1 + Your secondary battery is empty + + + False + True + 1 + + + + + False + False + 2 + + + + + False + True + 0 + + + + + False + True + + + False + True + 1 + + + + + False + False + 1 + + + + + True + False + 53 + 40 + 0 + 0.49000000953674316 + 4 + Tip: <a href="moo">Screen Settings</a> affect how much power is used + True + False + + + False + False + 2 + + + + + True + False + 15 + vertical + 24 + + + True + False + + + False + True + 0 + + + + + True + False + 9 + 28 + 15 + 18 + 6 + True + + + + + + + + + False + True + 1 + + + + + False + False + 3 + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/.quilt_patches gnome-control-center-3.6.3/.pc/.quilt_patches --- gnome-control-center-3.6.3/.pc/.quilt_patches 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/.quilt_patches 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1 @@ +/home/buildd/build-RECIPEBRANCHBUILD-874789/chroot-autobuild/home/buildd/work/tree/gnome-control-center-3.6.3/debian/patches diff -Nru gnome-control-center-3.6.3/.pc/.quilt_series gnome-control-center-3.6.3/.pc/.quilt_series --- gnome-control-center-3.6.3/.pc/.quilt_series 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/.quilt_series 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1 @@ +/home/buildd/build-RECIPEBRANCHBUILD-874789/chroot-autobuild/home/buildd/work/tree/gnome-control-center-3.6.3/debian/patches/series diff -Nru gnome-control-center-3.6.3/.pc/rename_screenshot_media_keys.patch/panels/keyboard/01-screenshot.xml.in gnome-control-center-3.6.3/.pc/rename_screenshot_media_keys.patch/panels/keyboard/01-screenshot.xml.in --- gnome-control-center-3.6.3/.pc/rename_screenshot_media_keys.patch/panels/keyboard/01-screenshot.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/rename_screenshot_media_keys.patch/panels/keyboard/01-screenshot.xml.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff -Nru gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/configure.ac gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/configure.ac --- gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,542 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.5.91 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/bluetooth-properties.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/panels/common/Makefile.am gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/panels/common/Makefile.am --- gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/panels/common/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/panels/common/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,44 @@ +# This is used in PANEL_CFLAGS +cappletname = common + +noinst_LTLIBRARIES = liblanguage.la +noinst_PROGRAMS = list-languages + +AM_CPPFLAGS = \ + $(PANEL_CFLAGS) \ + $(LIBLANGUAGE_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + -DUIDIR=\""$(pkgdatadir)/ui"\" \ + -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DUM_PIXMAP_DIR=\""$(pkgdatadir)/pixmaps"\" + +liblanguage_la_SOURCES = \ + gdm-languages.h \ + gdm-languages.c \ + locarchive.h \ + cc-common-language.c \ + cc-common-language.h \ + cc-language-chooser.c \ + cc-language-chooser.h + +liblanguage_la_LIBADD = \ + $(LIBLANGUAGE_LIBS) + +liblanguage_la_LDFLAGS = -export_dynamic -avoid-version -module -no-undefined + +list_languages_SOURCES = list-languages.c +list_languages_LDADD = liblanguage.la +list_languages_CFLAGS = $(LIBLANGUAGE_CFLAGS) + +uidir = $(pkgdatadir)/ui + +dist_ui_DATA = \ + language-chooser.ui + +rulesdir = $(datadir)/polkit-1/rules.d/ +rules_DATA = gnome-control-center.rules + +EXTRA_DIST = $(rules_DATA) + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/gnome-control-center.c gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/gnome-control-center.c --- gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/gnome-control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/gnome-control-center.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1449 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + + +#include "gnome-control-center.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ +#define GMENU_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "cc-panel.h" +#include "cc-shell.h" +#include "cc-shell-category-view.h" +#include "cc-shell-model.h" +#include "cc-shell-nav-bar.h" + +G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) + +#define CONTROL_CENTER_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_CONTROL_CENTER, GnomeControlCenterPrivate)) + +#define W(b,x) GTK_WIDGET (gtk_builder_get_object (b, x)) + +/* Use a fixed width for the shell, since resizing horizontally is more awkward + * for the user than resizing vertically + * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ +#define FIXED_WIDTH 740 +#define UNITY_FIXED_WIDTH 850 +#define FIXED_HEIGHT 650 +#define SMALL_SCREEN_FIXED_HEIGHT 400 + +#define MIN_ICON_VIEW_HEIGHT 300 + +typedef enum { + SMALL_SCREEN_UNSET, + SMALL_SCREEN_TRUE, + SMALL_SCREEN_FALSE +} CcSmallScreen; + +struct _GnomeControlCenterPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GtkWidget *main_vbox; + GtkWidget *scrolled_window; + GtkWidget *search_scrolled; + GtkWidget *current_panel_box; + GtkWidget *current_panel; + char *current_panel_id; + GtkWidget *window; + GtkWidget *search_entry; + GtkWidget *lock_button; + GPtrArray *custom_widgets; + GtkWidget *nav_bar; + + GMenuTree *menu_tree; + GtkListStore *store; + GHashTable *category_views; + + GtkTreeModel *search_filter; + GtkWidget *search_view; + gchar *filter_string; + + guint32 last_time; + + GIOExtensionPoint *extension_point; + + gchar *default_window_title; + gchar *default_window_icon; + + int monitor_num; + CcSmallScreen small_screen; +}; + +/* Notebook helpers */ +static GtkWidget * +notebook_get_selected_page (GtkWidget *notebook) +{ + int curr; + + curr = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + if (curr == -1) + return NULL; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), curr); +} + +static void +notebook_select_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't select GtkNotebook page %p", page); +} + +static void +notebook_remove_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't find GtkNotebook page to remove %p", page); +} + +static void +notebook_add_page (GtkWidget *notebook, + GtkWidget *page) +{ + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); +} + +static const gchar * +get_icon_name_from_g_icon (GIcon *gicon) +{ + const gchar * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return names[i]; + } + + return NULL; +} + +static gboolean +activate_panel (GnomeControlCenter *shell, + const gchar *id, + const gchar **argv, + const gchar *desktop_file, + const gchar *name, + GIcon *gicon) +{ + GnomeControlCenterPrivate *priv = shell->priv; + GType panel_type = G_TYPE_INVALID; + GList *panels, *l; + GtkWidget *box; + const gchar *icon_name; + + /* check if there is an plugin that implements this panel */ + panels = g_io_extension_point_get_extensions (priv->extension_point); + + if (!desktop_file) + return FALSE; + if (!id) + return FALSE; + + for (l = panels; l != NULL; l = l->next) + { + GIOExtension *extension; + const gchar *name; + + extension = l->data; + + name = g_io_extension_get_name (extension); + + if (!g_strcmp0 (name, id)) + { + panel_type = g_io_extension_get_type (extension); + break; + } + } + + if (panel_type == G_TYPE_INVALID) + { + g_warning ("Could not find the loadable module for panel '%s'", id); + return FALSE; + } + + /* create the panel plugin */ + priv->current_panel = g_object_new (panel_type, "shell", shell, "argv", argv, NULL); + cc_shell_set_active_panel (CC_SHELL (shell), CC_PANEL (priv->current_panel)); + gtk_widget_show (priv->current_panel); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), + cc_panel_get_permission (CC_PANEL (priv->current_panel))); + + box = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (box), 6, 6, 6, 6); + + gtk_container_add (GTK_CONTAINER (box), priv->current_panel); + + gtk_widget_set_name (box, id); + notebook_add_page (priv->notebook, box); + + /* switch to the new panel */ + gtk_widget_show (box); + notebook_select_page (priv->notebook, box); + cc_shell_nav_bar_show_detail_button (CC_SHELL_NAV_BAR(shell->priv->nav_bar), name); + + /* set the title of the window */ + icon_name = get_icon_name_from_g_icon (gicon); + gtk_window_set_role (GTK_WINDOW (priv->window), id); + gtk_window_set_title (GTK_WINDOW (priv->window), name); + gtk_window_set_default_icon_name (icon_name); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), icon_name); + + priv->current_panel_box = box; + + return TRUE; +} + +static void +_shell_remove_all_custom_widgets (GnomeControlCenterPrivate *priv) +{ + GtkBox *box; + GtkWidget *widget; + guint i; + + /* remove from the header */ + box = GTK_BOX (W (priv->builder, "topright")); + for (i = 0; i < priv->custom_widgets->len; i++) + { + widget = g_ptr_array_index (priv->custom_widgets, i); + gtk_container_remove (GTK_CONTAINER (box), widget); + } + g_ptr_array_set_size (priv->custom_widgets, 0); +} + +static void +shell_show_overview_page (GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + + notebook_select_page (priv->notebook, priv->scrolled_window); + + if (priv->current_panel_box) + notebook_remove_page (priv->notebook, priv->current_panel_box); + priv->current_panel = NULL; + priv->current_panel_box = NULL; + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear the search text */ + g_free (priv->filter_string); + priv->filter_string = g_strdup (""); + gtk_entry_set_text (GTK_ENTRY (priv->search_entry), ""); + gtk_widget_grab_focus (priv->search_entry); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), NULL); + + /* reset window title and icon */ + gtk_window_set_role (GTK_WINDOW (priv->window), NULL); + gtk_window_set_title (GTK_WINDOW (priv->window), priv->default_window_title); + gtk_window_set_default_icon_name (priv->default_window_icon); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), + priv->default_window_icon); + + cc_shell_set_active_panel (CC_SHELL (center), NULL); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + cc_shell_nav_bar_hide_detail_button (CC_SHELL_NAV_BAR (priv->nav_bar)); +} + +void +gnome_control_center_set_overview_page (GnomeControlCenter *center) +{ + shell_show_overview_page (center); +} + +static void +item_activated_cb (CcShellCategoryView *view, + gchar *name, + gchar *id, + gchar *desktop_file, + GnomeControlCenter *shell) +{ + GError *err = NULL; + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, &err)) + { + /* TODO: show message to user */ + if (err) + { + g_warning ("Could not active panel \"%s\": %s", id, err->message); + g_error_free (err); + } + } +} + +static gboolean +category_focus_out (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + gtk_icon_view_unselect_all (GTK_ICON_VIEW (view)); + + return FALSE; +} + +static gboolean +category_focus_in (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + GtkTreePath *path; + + if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL)) + { + path = gtk_tree_path_new_from_indices (0, -1); + gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE); + } + + gtk_icon_view_select_path (GTK_ICON_VIEW (view), path); + gtk_tree_path_free (path); + + return FALSE; +} + +static GList * +get_item_views (GnomeControlCenter *shell) +{ + GList *list, *l; + GList *res; + + list = gtk_container_get_children (GTK_CONTAINER (shell->priv->main_vbox)); + res = NULL; + for (l = list; l; l = l->next) + { + if (!CC_IS_SHELL_CATEGORY_VIEW (l->data)) + continue; + res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data))); + } + + g_list_free (list); + + return res; +} + +static gboolean +keynav_failed (GtkIconView *current_view, + GtkDirectionType direction, + GnomeControlCenter *shell) +{ + GList *views, *v; + GtkIconView *new_view; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + gint col, c, dist, d; + GtkTreePath *sel; + gboolean res; + + res = FALSE; + + views = get_item_views (shell); + + for (v = views; v; v = v->next) + { + if (v->data == current_view) + break; + } + + if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL) + { + new_view = v->next->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d < dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL) + { + new_view = v->prev->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d <= dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + g_list_free (views); + + return res; +} + +static gboolean +model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GnomeControlCenterPrivate *priv) +{ + gchar *name, *description; + gchar *needle, *haystack; + gboolean result; + gchar **keywords; + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + COL_DESCRIPTION, &description, + COL_KEYWORDS, &keywords, + -1); + + if (!priv->filter_string || !name) + { + g_free (name); + g_free (description); + g_strfreev (keywords); + return FALSE; + } + + needle = g_utf8_casefold (priv->filter_string, -1); + haystack = g_utf8_casefold (name, -1); + + result = (strstr (haystack, needle) != NULL); + + if (!result && description) + { + gchar *folded; + + folded = g_utf8_casefold (description, -1); + result = (strstr (folded, needle) != NULL); + g_free (folded); + } + + if (!result && keywords) + { + gint i; + gchar *keyword; + + for (i = 0; !result && keywords[i]; i++) + { + keyword = g_utf8_casefold (keywords[i], -1); + result = strstr (keyword, needle) == keyword; + g_free (keyword); + } + } + + g_free (name); + g_free (haystack); + g_free (needle); + g_strfreev (keywords); + + return result; +} + +static gboolean +category_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gchar *filter) +{ + gchar *category; + gboolean result; + + gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1); + + result = (g_strcmp0 (category, filter) == 0); + + g_free (category); + + return result; +} + +static void +search_entry_changed_cb (GtkEntry *entry, + GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + char *str; + + /* if the entry text was set manually (not by the user) */ + if (!g_strcmp0 (priv->filter_string, gtk_entry_get_text (entry))) + return; + + /* Don't re-filter for added trailing or leading spaces */ + str = g_strdup (gtk_entry_get_text (entry)); + g_strstrip (str); + if (!g_strcmp0 (str, priv->filter_string)) + { + g_free (str); + return; + } + + g_free (priv->filter_string); + priv->filter_string = str; + + if (!g_strcmp0 (priv->filter_string, "")) + { + shell_show_overview_page (center); + } + else + { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->search_filter)); + notebook_select_page (priv->notebook, priv->search_scrolled); + } +} + +static gboolean +search_entry_key_press_event_cb (GtkEntry *entry, + GdkEventKey *event, + GnomeControlCenterPrivate *priv) +{ + if (event->keyval == GDK_KEY_Return) + { + GtkTreePath *path; + + path = gtk_tree_path_new_first (); + + priv->last_time = event->time; + + gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->search_view), path); + + gtk_tree_path_free (path); + return TRUE; + } + + if (event->keyval == GDK_KEY_Escape) + { + gtk_entry_set_text (entry, ""); + return TRUE; + } + + return FALSE; +} + +static void +on_search_selection_changed (GtkTreeSelection *selection, + GnomeControlCenter *shell) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + COL_ID, &id, + -1); + + if (id) + cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); + + gtk_tree_selection_unselect_all (selection); + + g_free (id); +} + +static void +setup_search (GnomeControlCenter *shell) +{ + GtkWidget *search_view, *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GnomeControlCenterPrivate *priv = shell->priv; + + g_return_if_fail (priv->store != NULL); + + /* create the search filter */ + priv->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), + NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->search_filter), + (GtkTreeModelFilterVisibleFunc) + model_filter_func, + priv, NULL); + + /* set up the search view */ + priv->search_view = search_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), + GTK_TREE_MODEL (priv->search_filter)); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + "xpad", 15, + "ypad", 10, + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, + "gicon", COL_GICON, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 0, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", COL_NAME, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 15, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Description", renderer, + "text", COL_DESCRIPTION, + NULL); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + priv->search_scrolled = W (priv->builder, "search-scrolled-window"); + gtk_container_add (GTK_CONTAINER (priv->search_scrolled), search_view); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->search_view)), + "changed", + G_CALLBACK (on_search_selection_changed), + shell); + + /* setup the search entry widget */ + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "search-entry"); + priv->search_entry = widget; + priv->filter_string = g_strdup (""); + + g_signal_connect (widget, "changed", G_CALLBACK (search_entry_changed_cb), + shell); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (search_entry_key_press_event_cb), priv); + + gtk_widget_show (priv->search_view); +} + +static void +setup_lock (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + priv->lock_button = W (priv->builder, "lock-button"); +} + +static void +maybe_add_category_view (GnomeControlCenter *shell, + const char *name) +{ + GtkTreeModel *filter; + GtkWidget *categoryview; + + if (g_hash_table_lookup (shell->priv->category_views, name) != NULL) + return; + + if (g_hash_table_size (shell->priv->category_views) > 0) + { + GtkWidget *separator; + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_set_margin_top (separator, 11); + gtk_widget_set_margin_bottom (separator, 10); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), separator, FALSE, FALSE, 0); + gtk_widget_show (separator); + } + + /* create new category view for this category */ + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->priv->store), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + (GtkTreeModelFilterVisibleFunc) category_filter_func, + g_strdup (name), g_free); + + categoryview = cc_shell_category_view_new (name, filter); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), categoryview, FALSE, TRUE, 0); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "desktop-item-activated", + G_CALLBACK (item_activated_cb), shell); + + gtk_widget_show (categoryview); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-in-event", + G_CALLBACK (category_focus_in), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-out-event", + G_CALLBACK (category_focus_out), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "keynav-failed", + G_CALLBACK (keynav_failed), shell); + + g_hash_table_insert (shell->priv->category_views, g_strdup (name), categoryview); +} + +static void +reload_menu (GnomeControlCenter *shell) +{ + GError *error; + GMenuTreeDirectory *d; + GMenuTreeIter *iter; + GMenuTreeItemType next_type; + + error = NULL; + if (!gmenu_tree_load_sync (shell->priv->menu_tree, &error)) + { + g_warning ("Could not load control center menu: %s", error->message); + g_clear_error (&error); + return; + } + + + d = gmenu_tree_get_root_directory (shell->priv->menu_tree); + iter = gmenu_tree_directory_iter (d); + + while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) + { + if (next_type == GMENU_TREE_ITEM_DIRECTORY) + { + GMenuTreeDirectory *subdir; + const gchar *dir_name; + GMenuTreeIter *sub_iter; + GMenuTreeItemType sub_next_type; + + subdir = gmenu_tree_iter_get_directory (iter); + dir_name = gmenu_tree_directory_get_name (subdir); + + maybe_add_category_view (shell, dir_name); + + /* add the items from this category to the model */ + sub_iter = gmenu_tree_directory_iter (subdir); + while ((sub_next_type = gmenu_tree_iter_next (sub_iter)) != GMENU_TREE_ITEM_INVALID) + { + if (sub_next_type == GMENU_TREE_ITEM_ENTRY) + { + GMenuTreeEntry *item = gmenu_tree_iter_get_entry (sub_iter); + cc_shell_model_add_item (CC_SHELL_MODEL (shell->priv->store), + dir_name, + item); + gmenu_tree_item_unref (item); + } + } + + gmenu_tree_iter_unref (sub_iter); + gmenu_tree_item_unref (subdir); + } + } + + gmenu_tree_iter_unref (iter); +} + +static void +on_menu_changed (GMenuTree *monitor, + GnomeControlCenter *shell) +{ + gtk_list_store_clear (shell->priv->store); + reload_menu (shell); +} + +static void +setup_model (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + gtk_widget_set_margin_top (shell->priv->main_vbox, 8); + gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8); + gtk_widget_set_margin_left (shell->priv->main_vbox, 12); + gtk_widget_set_margin_right (shell->priv->main_vbox, 12); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window))); + + priv->store = (GtkListStore *) cc_shell_model_new (); + priv->category_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->menu_tree = gmenu_tree_new_for_path (MENUDIR "/gnomecc.menu", 0); + + reload_menu (shell); + + g_signal_connect (priv->menu_tree, "changed", G_CALLBACK (on_menu_changed), shell); +} + +static void +load_panel_plugins (GnomeControlCenter *shell) +{ + GList *modules; + + /* only allow this function to be run once to prevent modules being loaded + * twice + */ + if (shell->priv->extension_point) + return; + + /* make sure the base type is registered */ + g_type_from_name ("CcPanel"); + + shell->priv->extension_point + = g_io_extension_point_register (CC_SHELL_PANEL_EXTENSION_POINT); + + /* load all the plugins in the panels directory */ + modules = g_io_modules_load_all_in_directory (PANELS_DIR); + g_list_free (modules); + +} + + +static void +home_button_clicked_cb (GtkButton *button, + GnomeControlCenter *shell) +{ + shell_show_overview_page (shell); +} + +static void +notebook_page_notify_cb (GtkNotebook *notebook, + GParamSpec *spec, + GnomeControlCenterPrivate *priv) +{ + int nat_height; + GtkWidget *child; + + child = notebook_get_selected_page (GTK_WIDGET (notebook)); + + if (child == priv->scrolled_window || child == priv->search_scrolled) + { + gtk_widget_show (W (priv->builder, "search-entry")); + gtk_widget_hide (W (priv->builder, "lock-button")); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + UNITY_FIXED_WIDTH, NULL, &nat_height); + else + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); + } + else + { + gtk_widget_hide (W (priv->builder, "search-entry")); + /* set the scrolled window small so that it doesn't force + the window to be larger than this panel */ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + UNITY_FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + UNITY_FIXED_WIDTH, + nat_height); + } + else { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } + } +} + +/* CcShell implementation */ +static void +_shell_embed_widget_in_header (CcShell *shell, + GtkWidget *widget) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkBox *box; + + /* add to header */ + box = GTK_BOX (W (priv->builder, "topright")); + gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + g_ptr_array_add (priv->custom_widgets, g_object_ref (widget)); +} + +/* CcShell implementation */ +static gboolean +_shell_set_active_panel_from_id (CcShell *shell, + const gchar *start_id, + const gchar **argv, + GError **err) +{ + GtkTreeIter iter; + gboolean iter_valid; + gchar *name = NULL; + gchar *desktop = NULL; + GIcon *gicon = NULL; + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkWidget *old_panel; + + /* When loading the same panel again, just set the argv */ + if (g_strcmp0 (priv->current_panel_id, start_id) == 0) + { + g_object_set (G_OBJECT (priv->current_panel), "argv", argv, NULL); + return TRUE; + } + + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + + /* find the details for this item */ + while (iter_valid) + { + gchar *id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + COL_NAME, &name, + COL_DESKTOP_FILE, &desktop, + COL_GICON, &gicon, + COL_ID, &id, + -1); + + if (id && !strcmp (id, start_id)) + { + g_free (id); + break; + } + else + { + g_free (id); + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + name = NULL; + id = NULL; + desktop = NULL; + gicon = NULL; + } + + iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + if (!name) + { + g_warning ("Could not find settings panel \"%s\"", start_id); + } + else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop, + name, gicon) == FALSE) + { + /* Failed to activate the panel for some reason */ + old_panel = priv->current_panel_box; + priv->current_panel_box = NULL; + notebook_select_page (priv->notebook, priv->scrolled_window); + if (old_panel) + notebook_remove_page (priv->notebook, old_panel); + } + else + { + priv->current_panel_id = g_strdup (start_id); + } + + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + return TRUE; +} + +static GtkWidget * +_shell_get_toplevel (CcShell *shell) +{ + return GNOME_CONTROL_CENTER (shell)->priv->window; +} + +/* GObject Implementation */ +static void +gnome_control_center_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_dispose (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + g_free (priv->current_panel_id); + + if (priv->custom_widgets) + { + g_ptr_array_unref (priv->custom_widgets); + priv->custom_widgets = NULL; + } + if (priv->window) + { + gtk_widget_destroy (priv->window); + priv->window = NULL; + + /* destroying the window will destroy its children */ + priv->notebook = NULL; + priv->search_entry = NULL; + priv->search_view = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->store) + { + g_object_unref (priv->store); + priv->store = NULL; + } + + if (priv->search_filter) + { + g_object_unref (priv->search_filter); + priv->search_filter = NULL; + } + + + G_OBJECT_CLASS (gnome_control_center_parent_class)->dispose (object); +} + +static void +gnome_control_center_finalize (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + if (priv->filter_string) + { + g_free (priv->filter_string); + priv->filter_string = NULL; + } + + if (priv->default_window_title) + { + g_free (priv->default_window_title); + priv->default_window_title = NULL; + } + + if (priv->default_window_icon) + { + g_free (priv->default_window_icon); + priv->default_window_icon = NULL; + } + + if (priv->menu_tree) + { + g_signal_handlers_disconnect_by_func (priv->menu_tree, + G_CALLBACK (on_menu_changed), object); + g_object_unref (priv->menu_tree); + } + + if (priv->category_views) + { + g_hash_table_destroy (priv->category_views); + } + + G_OBJECT_CLASS (gnome_control_center_parent_class)->finalize (object); +} + +static void +gnome_control_center_class_init (GnomeControlCenterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcShellClass *shell_class = CC_SHELL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GnomeControlCenterPrivate)); + + object_class->get_property = gnome_control_center_get_property; + object_class->set_property = gnome_control_center_set_property; + object_class->dispose = gnome_control_center_dispose; + object_class->finalize = gnome_control_center_finalize; + + shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id; + shell_class->embed_widget_in_header = _shell_embed_widget_in_header; + shell_class->get_toplevel = _shell_get_toplevel; +} + +static gboolean +window_key_press_event (GtkWidget *win, + GdkEventKey *event, + GnomeControlCenter *self) +{ + GdkKeymap *keymap; + gboolean retval; + GdkModifierType state; + + if (event->state == 0) + return FALSE; + + retval = FALSE; + state = event->state; + keymap = gdk_keymap_get_default (); + gdk_keymap_add_virtual_modifiers (keymap, &state); + state = state & gtk_accelerator_get_default_mod_mask (); + + if (state == GDK_CONTROL_MASK) + { + switch (event->keyval) + { + case GDK_KEY_s: + case GDK_KEY_S: + case GDK_KEY_f: + case GDK_KEY_F: + if (gtk_widget_get_visible (self->priv->search_entry)) + { + gtk_widget_grab_focus (self->priv->search_entry); + retval = TRUE; + } + break; + case GDK_KEY_Q: + case GDK_KEY_q: + g_object_unref (self); + retval = TRUE; + break; + case GDK_KEY_W: + case GDK_KEY_w: + if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) + shell_show_overview_page (self); + retval = TRUE; + break; + } + } + return retval; +} + +static gint +get_monitor_height (GnomeControlCenter *self) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* We cannot use workarea here, as this wouldn't + * be updated when we read it after a monitors-changed signal */ + screen = gtk_widget_get_screen (self->priv->window); + gdk_screen_get_monitor_geometry (screen, self->priv->monitor_num, &rect); + + return rect.height; +} + +static gboolean +update_monitor_number (GnomeControlCenter *self) +{ + gboolean changed = FALSE; + GtkWidget *widget; + GdkScreen *screen; + GdkWindow *window; + int monitor; + + widget = self->priv->window; + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (widget); + monitor = gdk_screen_get_monitor_at_window (screen, window); + if (self->priv->monitor_num != monitor) + { + self->priv->monitor_num = monitor; + changed = TRUE; + } + + return changed; +} + +static CcSmallScreen +is_small (GnomeControlCenter *self) +{ + if (get_monitor_height (self) <= FIXED_HEIGHT) + return SMALL_SCREEN_TRUE; + return SMALL_SCREEN_FALSE; +} + +static void +update_small_screen_settings (GnomeControlCenter *self) +{ + CcSmallScreen small; + + update_monitor_number (self); + small = is_small (self); + + if (small == SMALL_SCREEN_TRUE) + { + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), TRUE); + + if (self->priv->small_screen != small) + gtk_window_maximize (GTK_WINDOW (self->priv->window)); + } + else + { + if (self->priv->small_screen != small) + gtk_window_unmaximize (GTK_WINDOW (self->priv->window)); + + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), FALSE); + } + + self->priv->small_screen = small; + + /* And update the minimum sizes */ + notebook_page_notify_cb (GTK_NOTEBOOK (self->priv->notebook), NULL, self->priv); +} + +static gboolean +main_window_configure_cb (GtkWidget *widget, + GdkEvent *event, + GnomeControlCenter *self) +{ + update_small_screen_settings (self); + return FALSE; +} + +static void +application_set_cb (GObject *object, + GParamSpec *pspec, + GnomeControlCenter *self) +{ + /* update small screen settings now - to avoid visible resizing, we want + * to do it before showing the window, and GtkApplicationWindow cannot be + * realized unless its application property has been set */ + if (gtk_window_get_application (GTK_WINDOW (self->priv->window))) + { + gtk_widget_realize (self->priv->window); + update_small_screen_settings (self); + } +} + +static void +monitors_changed_cb (GdkScreen *screen, + GnomeControlCenter *self) +{ + /* We reset small_screen_set to make sure that the + * window gets maximised if need be, in update_small_screen_settings() */ + self->priv->small_screen = SMALL_SCREEN_UNSET; + update_small_screen_settings (self); +} + +static void +gnome_control_center_init (GnomeControlCenter *self) +{ + GError *err = NULL; + GnomeControlCenterPrivate *priv; + GdkScreen *screen; + GtkWidget *widget; + + priv = self->priv = CONTROL_CENTER_PRIVATE (self); + +#ifdef HAVE_CHEESE + if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + { + g_critical ("Clutter-GTK init failed"); + return; + } +#endif /* HAVE_CHEESE */ + + priv->monitor_num = -1; + self->priv->small_screen = SMALL_SCREEN_UNSET; + + /* load the user interface */ + priv->builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (priv->builder, UIDIR "/shell.ui", &err)) + { + g_critical ("Could not build interface: %s", err->message); + g_error_free (err); + + return; + } + + /* connect various signals */ + priv->window = W (priv->builder, "main-window"); + gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (priv->window), TRUE); + screen = gtk_widget_get_screen (priv->window); + g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self); + g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self); + g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self); + g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self); + g_signal_connect_after (priv->window, "key_press_event", + G_CALLBACK (window_key_press_event), self); + + priv->notebook = W (priv->builder, "notebook"); + + /* Main scrolled window */ + priv->scrolled_window = W (priv->builder, "scrolledwindow1"); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); + else + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + priv->main_vbox = W (priv->builder, "main-vbox"); + g_signal_connect (priv->notebook, "notify::page", + G_CALLBACK (notebook_page_notify_cb), priv); + + priv->nav_bar = cc_shell_nav_bar_new (); + widget = W (priv->builder, "hbox1"); + gtk_box_pack_start (GTK_BOX (widget), priv->nav_bar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (widget), priv->nav_bar, 0); + gtk_widget_show (priv->nav_bar); + + g_signal_connect (priv->nav_bar, + "home-clicked", G_CALLBACK (home_button_clicked_cb), self); + + /* keep a list of custom widgets to unload on panel change */ + priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* load the available settings panels */ + setup_model (self); + + /* load the panels that are implemented as plugins */ + load_panel_plugins (self); + + /* setup search functionality */ + setup_search (self); + + setup_lock (self); + + /* store default window title and name */ + priv->default_window_title = g_strdup (gtk_window_get_title (GTK_WINDOW (priv->window))); + priv->default_window_icon = g_strdup (gtk_window_get_icon_name (GTK_WINDOW (priv->window))); + + notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv); +} + +GnomeControlCenter * +gnome_control_center_new (void) +{ + return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL); +} + +void +gnome_control_center_present (GnomeControlCenter *center) +{ + gtk_window_present (GTK_WINDOW (center->priv->window)); +} + +void +gnome_control_center_show (GnomeControlCenter *center, + GtkApplication *app) +{ + gtk_window_set_application (GTK_WINDOW (center->priv->window), app); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window))); +} diff -Nru gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/Makefile.am gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/Makefile.am --- gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/revert_git_drop_library.patch/shell/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,79 @@ +INCLUDES = \ + -I$(top_srcdir) \ + $(SHELL_CFLAGS) \ + $(CHEESE_CFLAGS) + +bin_PROGRAMS = gnome-control-center + +MARSHAL_FILES = cc-shell-marshal.c cc-shell-marshal.h +BUILT_SOURCES = $(MARSHAL_FILES) + +cc-shell-marshal.h: cc-shell-marshal.list + $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=cc_shell_marshal $< --header > $@ + +cc-shell-marshal.c: cc-shell-marshal.list + $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=cc_shell_marshal $< --body --header > $@ + +gnome_control_center_SOURCES = \ + control-center.c \ + cc-shell-log.c \ + cc-shell-log.h \ + gnome-control-center.c \ + gnome-control-center.h \ + cc-shell-category-view.c \ + cc-shell-category-view.h \ + cc-shell-item-view.c \ + cc-shell-item-view.h \ + cc-shell-model.c \ + cc-shell-model.h \ + cc-shell-nav-bar.c \ + cc-shell-nav-bar.h \ + cc-editable-entry.c \ + cc-editable-entry.h \ + cc-panel.c \ + cc-panel.h \ + cc-shell.c \ + cc-shell.h \ + $(MARSHAL_FILES) + +gnome_control_center_LDADD = \ + $(SHELL_LIBS) \ + $(CHEESE_LIBS) + +gnome_control_center_LDFLAGS = -export-dynamic + +AM_CPPFLAGS = \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + -DUIDIR="\"$(uidir)\"" \ + -DMENUDIR="\"$(menudir)\"" \ + -DPANELS_DIR="\"$(PANELS_DIR)\"" + +menudir = $(sysconfdir)/xdg/menus +menu_DATA = gnomecc.menu + +gnomecc.menu: gnomecc.menu.in + $(AM_V_GEN) cat $< | sed 's,@applicationsdir@,$(datadir)/applications/,' > $@ + +uidir = $(pkgdatadir)/ui +ui_DATA = shell.ui + +sysdir = $(datadir)/applications +sys_in_files = gnome-control-center.desktop.in +sys_DATA = $(sys_in_files:.desktop.in=.desktop) +@INTLTOOL_DESKTOP_RULE@ + +directorydir = $(datadir)/desktop-directories +directory_in_files = gnomecc.directory.in +directory_DATA = $(directory_in_files:.directory.in=.directory) +@INTLTOOL_DIRECTORY_RULE@ + +EXTRA_DIST = \ + $(ui_DATA) \ + gnome-control-center.desktop.in.in \ + gnomecc.directory.in \ + gnomecc.menu.in \ + cc-shell-marshal.list + +DISTCLEANFILES = gnome-control-center.desktop gnome-control-center.desktop.in gnomecc.directory gnomecc.menu + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/sanitize_ssid_convert_utf8.patch/panels/network/net-device-wifi.c gnome-control-center-3.6.3/.pc/sanitize_ssid_convert_utf8.patch/panels/network/net-device-wifi.c --- gnome-control-center-3.6.3/.pc/sanitize_ssid_convert_utf8.patch/panels/network/net-device-wifi.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/sanitize_ssid_convert_utf8.patch/panels/network/net-device-wifi.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,2186 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2011-2012 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include + +//#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "network-dialogs.h" +#include "panel-common.h" +#include "panel-cell-renderer-mode.h" +#include "panel-cell-renderer-signal.h" +#include "panel-cell-renderer-security.h" +#include "panel-cell-renderer-separator.h" +#include "panel-cell-renderer-text.h" +#include "panel-cell-renderer-pixbuf.h" + +#include "net-device-wifi.h" + +#define NET_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NET_TYPE_DEVICE_WIFI, NetDeviceWifiPrivate)) + +static void nm_device_wifi_refresh_ui (NetDeviceWifi *device_wifi); +static void show_wifi_list (NetDeviceWifi *device_wifi); + +struct _NetDeviceWifiPrivate +{ + GtkBuilder *builder; + gboolean updating_device; + gchar *selected_ssid_title; + gchar *selected_connection_id; + gchar *selected_ap_id; +}; + +G_DEFINE_TYPE (NetDeviceWifi, net_device_wifi, NET_TYPE_DEVICE) + +enum { + COLUMN_CONNECTION_ID, + COLUMN_ACCESS_POINT_ID, + COLUMN_TITLE, + COLUMN_SORT, + COLUMN_STRENGTH, + COLUMN_MODE, + COLUMN_SECURITY, + COLUMN_ACTIVE, + COLUMN_AP_IN_RANGE, + COLUMN_AP_OUT_OF_RANGE, + COLUMN_AP_IS_SAVED, + COLUMN_LAST +}; + +static GtkWidget * +device_wifi_proxy_add_to_notebook (NetObject *object, + GtkNotebook *notebook, + GtkSizeGroup *heading_size_group) +{ + GtkWidget *widget; + GtkWindow *window; + NetDeviceWifi *device_wifi = NET_DEVICE_WIFI (object); + + /* add widgets to size group */ + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "heading_ipv4")); + gtk_size_group_add_widget (heading_size_group, widget); + + /* reparent */ + window = GTK_WINDOW (gtk_builder_get_object (device_wifi->priv->builder, + "window_tmp")); + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "notebook_view")); + g_object_ref (widget); + gtk_container_remove (GTK_CONTAINER (window), widget); + gtk_notebook_append_page (notebook, widget, NULL); + g_object_unref (widget); + + return widget; +} + +static guint +get_access_point_security (NMAccessPoint *ap) +{ + NM80211ApFlags flags; + NM80211ApSecurityFlags wpa_flags; + NM80211ApSecurityFlags rsn_flags; + guint type; + + flags = nm_access_point_get_flags (ap); + wpa_flags = nm_access_point_get_wpa_flags (ap); + rsn_flags = nm_access_point_get_rsn_flags (ap); + + if (!(flags & NM_802_11_AP_FLAGS_PRIVACY) && + wpa_flags == NM_802_11_AP_SEC_NONE && + rsn_flags == NM_802_11_AP_SEC_NONE) + type = NM_AP_SEC_NONE; + else if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && + wpa_flags == NM_802_11_AP_SEC_NONE && + rsn_flags == NM_802_11_AP_SEC_NONE) + type = NM_AP_SEC_WEP; + else if (!(flags & NM_802_11_AP_FLAGS_PRIVACY) && + wpa_flags != NM_802_11_AP_SEC_NONE && + rsn_flags != NM_802_11_AP_SEC_NONE) + type = NM_AP_SEC_WPA; + else + type = NM_AP_SEC_WPA2; + + return type; +} + +static void +add_access_point (NetDeviceWifi *device_wifi, NMAccessPoint *ap, NMAccessPoint *active, NMDevice *device) +{ + const GByteArray *ssid; + const gchar *object_path; + const gchar *ssid_text; + gboolean is_active_ap; + gchar *title; + GtkListStore *liststore_network; + GtkTreeIter treeiter; + NetDeviceWifiPrivate *priv = device_wifi->priv; + + ssid = nm_access_point_get_ssid (ap); + if (ssid == NULL) + return; + ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); + title = g_markup_escape_text (ssid_text, -1); + + is_active_ap = active && nm_utils_same_ssid (ssid, nm_access_point_get_ssid (active), TRUE); + liststore_network = GTK_LIST_STORE (gtk_builder_get_object (priv->builder, + "liststore_network")); + + object_path = nm_object_get_path (NM_OBJECT (ap)); + gtk_list_store_insert_with_values (liststore_network, + &treeiter, + -1, + COLUMN_ACCESS_POINT_ID, object_path, + COLUMN_TITLE, title, + COLUMN_SORT, ssid_text, + COLUMN_STRENGTH, nm_access_point_get_strength (ap), + COLUMN_MODE, nm_access_point_get_mode (ap), + COLUMN_SECURITY, get_access_point_security (ap), + COLUMN_ACTIVE, is_active_ap, + COLUMN_AP_IN_RANGE, TRUE, + COLUMN_AP_OUT_OF_RANGE, FALSE, + COLUMN_AP_IS_SAVED, FALSE, + -1); + g_free (title); +} + +static GPtrArray * +panel_get_strongest_unique_aps (const GPtrArray *aps) +{ + const GByteArray *ssid; + const GByteArray *ssid_tmp; + GPtrArray *aps_unique = NULL; + gboolean add_ap; + guint i; + guint j; + NMAccessPoint *ap; + NMAccessPoint *ap_tmp; + + /* we will have multiple entries for typical hotspots, just + * filter to the one with the strongest signal */ + aps_unique = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + if (aps != NULL) + for (i = 0; i < aps->len; i++) { + ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i)); + + /* Hidden SSIDs don't get shown in the list */ + ssid = nm_access_point_get_ssid (ap); + if (!ssid) + continue; + + add_ap = TRUE; + + /* get already added list */ + for (j=0; jlen; j++) { + ap_tmp = NM_ACCESS_POINT (g_ptr_array_index (aps_unique, j)); + ssid_tmp = nm_access_point_get_ssid (ap_tmp); + g_assert (ssid_tmp); + + /* is this the same type and data? */ + if (nm_utils_same_ssid (ssid, ssid_tmp, TRUE)) { + + g_debug ("found duplicate: %s", + nm_utils_escape_ssid (ssid_tmp->data, + ssid_tmp->len)); + + /* the new access point is stronger */ + if (nm_access_point_get_strength (ap) > + nm_access_point_get_strength (ap_tmp)) { + g_debug ("removing %s", + nm_utils_escape_ssid (ssid_tmp->data, + ssid_tmp->len)); + g_ptr_array_remove (aps_unique, ap_tmp); + add_ap = TRUE; + } else { + add_ap = FALSE; + } + + break; + } + } + if (add_ap) { + g_debug ("adding %s", + nm_utils_escape_ssid (ssid->data, + ssid->len)); + g_ptr_array_add (aps_unique, g_object_ref (ap)); + } + } + return aps_unique; +} + +static gchar * +get_ap_security_string (NMAccessPoint *ap) +{ + NM80211ApSecurityFlags wpa_flags, rsn_flags; + NM80211ApFlags flags; + GString *str; + + flags = nm_access_point_get_flags (ap); + wpa_flags = nm_access_point_get_wpa_flags (ap); + rsn_flags = nm_access_point_get_rsn_flags (ap); + + str = g_string_new (""); + if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && + (wpa_flags == NM_802_11_AP_SEC_NONE) && + (rsn_flags == NM_802_11_AP_SEC_NONE)) { + /* TRANSLATORS: this WEP WiFi security */ + g_string_append_printf (str, "%s, ", _("WEP")); + } + if (wpa_flags != NM_802_11_AP_SEC_NONE) { + /* TRANSLATORS: this WPA WiFi security */ + g_string_append_printf (str, "%s, ", _("WPA")); + } + if (rsn_flags != NM_802_11_AP_SEC_NONE) { + /* TRANSLATORS: this WPA WiFi security */ + g_string_append_printf (str, "%s, ", _("WPA2")); + } + if ((wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) || + (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + /* TRANSLATORS: this Enterprise WiFi security */ + g_string_append_printf (str, "%s, ", _("Enterprise")); + } + if (str->len > 0) + g_string_set_size (str, str->len - 2); + else { + g_string_append (str, C_("Wifi security", "None")); + } + return g_string_free (str, FALSE); +} + +static void +wireless_enabled_toggled (NMClient *client, + GParamSpec *pspec, + NetDeviceWifi *device_wifi) +{ + gboolean enabled; + GtkSwitch *sw; + NMDevice *device; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_WIFI) + return; + + enabled = nm_client_wireless_get_enabled (client); + sw = GTK_SWITCH (gtk_builder_get_object (device_wifi->priv->builder, + "device_off_switch")); + + device_wifi->priv->updating_device = TRUE; + gtk_switch_set_active (sw, enabled); + device_wifi->priv->updating_device = FALSE; +} + +#if 0 +static void +update_off_switch_from_device_state (GtkSwitch *sw, + NMDeviceState state, + NetDeviceWifi *device_wifi) +{ + device_wifi->priv->updating_device = TRUE; + switch (state) { + case NM_DEVICE_STATE_UNMANAGED: + case NM_DEVICE_STATE_UNAVAILABLE: + case NM_DEVICE_STATE_DISCONNECTED: + case NM_DEVICE_STATE_DEACTIVATING: + case NM_DEVICE_STATE_FAILED: + gtk_switch_set_active (sw, FALSE); + break; + default: + gtk_switch_set_active (sw, TRUE); + break; + } + device_wifi->priv->updating_device = FALSE; +} +#endif + +static NMConnection * +find_connection_for_device (NetDeviceWifi *device_wifi, + NMDevice *device) +{ + NetDevice *tmp; + NMConnection *connection; + NMRemoteSettings *remote_settings; + NMClient *client; + + client = net_object_get_client (NET_OBJECT (device_wifi)); + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + tmp = g_object_new (NET_TYPE_DEVICE, + "client", client, + "remote-settings", remote_settings, + "nm-device", device, + NULL); + connection = net_device_get_find_connection (tmp); + g_object_unref (tmp); + return connection; +} + +static gboolean +connection_is_shared (NMConnection *c) +{ + NMSettingIP4Config *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config (c); + if (g_strcmp0 (nm_setting_ip4_config_get_method (s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_SHARED) != 0) { + return FALSE; + } + + return TRUE; +} + +static gboolean +device_is_hotspot (NetDeviceWifi *device_wifi) +{ + NMConnection *c; + NMDevice *device; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + c = find_connection_for_device (device_wifi, device); + if (c == NULL) + return FALSE; + + return connection_is_shared (c); +} + +static const GByteArray * +device_get_hotspot_ssid (NetDeviceWifi *device_wifi, + NMDevice *device) +{ + NMConnection *c; + NMSettingWireless *sw; + + c = find_connection_for_device (device_wifi, device); + if (c == NULL) { + return FALSE; + } + + sw = nm_connection_get_setting_wireless (c); + return nm_setting_wireless_get_ssid (sw); +} + +static void +get_secrets_cb (NMRemoteConnection *c, + GHashTable *secrets, + GError *error, + gpointer data) +{ + NetDeviceWifi *device_wifi = data; + NMSettingWireless *sw; + + sw = nm_connection_get_setting_wireless (NM_CONNECTION (c)); + + nm_connection_update_secrets (NM_CONNECTION (c), + nm_setting_wireless_get_security (sw), + secrets, NULL); + + nm_device_wifi_refresh_ui (device_wifi); +} + +static void +device_get_hotspot_security_details (NetDeviceWifi *device_wifi, + NMDevice *device, + gchar **secret, + gchar **security) +{ + NMConnection *c; + NMSettingWireless *sw; + NMSettingWirelessSecurity *sws; + const gchar *key_mgmt; + const gchar *tmp_secret; + const gchar *tmp_security; + + c = find_connection_for_device (device_wifi, device); + if (c == NULL) + return; + + sw = nm_connection_get_setting_wireless (c); + sws = nm_connection_get_setting_wireless_security (c); + if (sw == NULL || sws == NULL) + return; + + tmp_secret = NULL; + tmp_security = C_("Wifi security", "None"); + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (sws); + if (strcmp (key_mgmt, "none") == 0) { + tmp_secret = nm_setting_wireless_security_get_wep_key (sws, 0); + tmp_security = _("WEP"); + } + else if (strcmp (key_mgmt, "wpa-none") == 0) { + tmp_secret = nm_setting_wireless_security_get_psk (sws); + tmp_security = _("WPA"); + } else { + g_warning ("unhandled security key-mgmt: %s", key_mgmt); + } + + /* If we don't have secrets, request them from NM and bail. + * We'll refresh the UI when secrets arrive. + */ + if (tmp_secret == NULL) { + nm_remote_connection_get_secrets ((NMRemoteConnection*)c, + nm_setting_wireless_get_security (sw), + get_secrets_cb, + device_wifi); + return; + } + + if (secret) + *secret = g_strdup (tmp_secret); + if (security) + *security = g_strdup (tmp_security); +} + +static void +device_wifi_refresh_aps (NetDeviceWifi *device_wifi) +{ + const GPtrArray *aps; + GPtrArray *aps_unique = NULL; + GtkListStore *liststore_network; + guint i; + NMAccessPoint *active_ap; + NMAccessPoint *ap; + NMDevice *nm_device; + + /* populate access points */ + liststore_network = GTK_LIST_STORE (gtk_builder_get_object (device_wifi->priv->builder, + "liststore_network")); + device_wifi->priv->updating_device = TRUE; + gtk_list_store_clear (liststore_network); + nm_device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (nm_device)); + aps_unique = panel_get_strongest_unique_aps (aps); + active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (nm_device)); + + for (i = 0; i < aps_unique->len; i++) { + ap = NM_ACCESS_POINT (g_ptr_array_index (aps_unique, i)); + add_access_point (device_wifi, ap, active_ap, nm_device); + } + + device_wifi->priv->updating_device = FALSE; + g_ptr_array_unref (aps_unique); +} + +static gboolean +find_ssid_in_store (GtkTreeModel *model, GtkTreeIter *iter, const gchar *ssid) +{ + gboolean found; + gchar *sort; + + found = gtk_tree_model_get_iter_first (model, iter); + + while (found) { + gtk_tree_model_get (model, iter, + COLUMN_SORT, &sort, + -1); + if (g_strcmp0 (ssid, sort) == 0) { + g_free (sort); + return TRUE; + } + g_free (sort); + found = gtk_tree_model_iter_next (model, iter); + } + + return FALSE; + +} + +static void +add_saved_connection (NetDeviceWifi *device_wifi, NMConnection *connection, NMDevice *nm_device) +{ + const GByteArray *ssid; + const gchar *id; + const gchar *ssid_text; + gchar *title; + GtkListStore *store; + GtkTreeIter iter; + NMSetting *setting; + + setting = nm_connection_get_setting_by_name (connection, NM_SETTING_WIRELESS_SETTING_NAME); + + if (setting == NULL) + return; + + ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (setting)); + ssid_text = nm_utils_escape_ssid (ssid->data, ssid->len); + title = g_markup_escape_text (ssid_text, -1); + g_debug ("got saved %s", title); + + id = nm_connection_get_path (connection); + + store = GTK_LIST_STORE (gtk_builder_get_object (device_wifi->priv->builder, + "liststore_network")); + if (find_ssid_in_store (GTK_TREE_MODEL (store), &iter, ssid_text)) + gtk_list_store_set (store, &iter, + COLUMN_CONNECTION_ID, id, + COLUMN_AP_IS_SAVED, TRUE, + -1); + else + gtk_list_store_insert_with_values (store, &iter, + -1, + COLUMN_CONNECTION_ID, id, + COLUMN_TITLE, title, + COLUMN_SORT, ssid_text, + COLUMN_STRENGTH, 0, + COLUMN_MODE, 0, + COLUMN_SECURITY, 0, + COLUMN_ACTIVE, FALSE, + COLUMN_AP_IN_RANGE, FALSE, + COLUMN_AP_OUT_OF_RANGE, TRUE, + COLUMN_AP_IS_SAVED, TRUE, + -1); + g_free (title); +} + +static void +device_wifi_refresh_saved_connections (NetDeviceWifi *device_wifi) +{ + GSList *connections; + GSList *filtered; + GSList *l; + NMDevice *nm_device; + NMRemoteSettings *remote_settings; + + /* add stored connections */ + device_wifi->priv->updating_device = TRUE; + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + connections = nm_remote_settings_list_connections (remote_settings); + nm_device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + filtered = nm_device_filter_connections (nm_device, connections); + for (l = filtered; l; l = l->next) { + NMConnection *connection = l->data; + if (!connection_is_shared (connection)) + add_saved_connection (device_wifi, connection, nm_device); + } + device_wifi->priv->updating_device = FALSE; + + g_slist_free (connections); + g_slist_free (filtered); +} + +static void +nm_device_wifi_refresh_hotspot (NetDeviceWifi *device_wifi) +{ + const GByteArray *ssid; + gchar *hotspot_secret = NULL; + gchar *hotspot_security = NULL; + gchar *hotspot_ssid = NULL; + NMDevice *nm_device; + + /* refresh hotspot ui */ + nm_device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + ssid = device_get_hotspot_ssid (device_wifi, nm_device); + if (ssid) + hotspot_ssid = nm_utils_ssid_to_utf8 (ssid); + device_get_hotspot_security_details (device_wifi, + nm_device, + &hotspot_secret, + &hotspot_security); + + panel_set_device_widget_details (device_wifi->priv->builder, + "hotspot_network_name", + hotspot_ssid); + panel_set_device_widget_details (device_wifi->priv->builder, + "hotspot_security_key", + hotspot_secret); + panel_set_device_widget_details (device_wifi->priv->builder, + "hotspot_security", + hotspot_security); + panel_set_device_widget_details (device_wifi->priv->builder, + "hotspot_connected", + NULL); + + g_free (hotspot_secret); + g_free (hotspot_security); + g_free (hotspot_ssid); +} + +static void +update_last_used (NetDeviceWifi *device_wifi) +{ + NetDeviceWifiPrivate *priv = device_wifi->priv; + gchar *last_used = NULL; + GDateTime *now = NULL; + GDateTime *then = NULL; + gint days; + GTimeSpan diff; + guint64 timestamp; + NMRemoteConnection *connection; + NMRemoteSettings *settings; + NMSettingConnection *s_con; + + if (priv->selected_connection_id == NULL) + goto out; + + settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + connection = nm_remote_settings_get_connection_by_path (settings, + priv->selected_connection_id); + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + if (s_con == NULL) + goto out; + timestamp = nm_setting_connection_get_timestamp (s_con); + if (timestamp == 0) { + last_used = g_strdup (_("never")); + goto out; + } + + /* calculate the amount of time that has elapsed */ + now = g_date_time_new_now_utc (); + then = g_date_time_new_from_unix_utc (timestamp); + diff = g_date_time_difference (now, then); + days = diff / G_TIME_SPAN_DAY; + if (days == 0) + last_used = g_strdup (_("today")); + else if (days == 1) + last_used = g_strdup (_("yesterday")); + else + last_used = g_strdup_printf (ngettext ("%i day ago", "%i days ago", days), days); +out: + panel_set_device_widget_details (device_wifi->priv->builder, + "last_used", + last_used); + if (now != NULL) + g_date_time_unref (now); + if (then != NULL) + g_date_time_unref (then); + g_free (last_used); +} + +static void +nm_device_wifi_refresh_ui (NetDeviceWifi *device_wifi) +{ + const gchar *str; + gboolean is_hotspot; + gchar *str_tmp = NULL; + GtkWidget *widget; + gint strength = 0; + guint speed = 0; + NMAccessPoint *active_ap; + NMDevice *nm_device; + NMDeviceState state; + NMClient *client; + NMAccessPoint *ap; + NetDeviceWifiPrivate *priv = device_wifi->priv; + + is_hotspot = device_is_hotspot (device_wifi); + if (is_hotspot) { + nm_device_wifi_refresh_hotspot (device_wifi); + return; + } + + nm_device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + + if (priv->selected_ap_id) { + ap = nm_device_wifi_get_access_point_by_path (NM_DEVICE_WIFI (nm_device), + priv->selected_ap_id); + } + else { + ap = NULL; + } + + active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (nm_device)); + + state = nm_device_get_state (nm_device); + + /* keep this in sync with the signal handler setup in cc_network_panel_init */ + client = net_object_get_client (NET_OBJECT (device_wifi)); + wireless_enabled_toggled (client, NULL, device_wifi); + + if (ap != active_ap) + speed = 0; + else if (state != NM_DEVICE_STATE_UNAVAILABLE) + speed = nm_device_wifi_get_bitrate (NM_DEVICE_WIFI (nm_device)); + speed /= 1000; + if (speed > 0) { + /* Translators: network device speed */ + str_tmp = g_strdup_printf (_("%d Mb/s"), speed); + } + panel_set_device_widget_details (device_wifi->priv->builder, + "speed", + str_tmp); + + /* set device state, with status and optionally speed */ + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "label_status")); + if (ap != active_ap) { + if (ap) + gtk_label_set_label (GTK_LABEL (widget), _("Not connected")); + else + gtk_label_set_label (GTK_LABEL (widget), _("Out of range")); + gtk_widget_set_tooltip_text (widget, ""); + } else { + gtk_label_set_label (GTK_LABEL (widget), + panel_device_state_to_localized_string (nm_device)); + gtk_widget_set_tooltip_text (widget, panel_device_state_reason_to_localized_string (nm_device)); + } + + /* device MAC */ + str = nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (nm_device)); + panel_set_device_widget_details (device_wifi->priv->builder, + "mac", + str); + /* security */ + if (ap != active_ap) + str_tmp = NULL; + else if (active_ap != NULL) + str_tmp = get_ap_security_string (active_ap); + panel_set_device_widget_details (device_wifi->priv->builder, + "security", + str_tmp); + g_free (str_tmp); + + /* signal strength */ + if (ap != NULL) + strength = nm_access_point_get_strength (ap); + else + strength = 0; + if (strength <= 0) + str = NULL; + else if (strength < 20) + str = C_("Signal strength", "None"); + else if (strength < 40) + str = C_("Signal strength", "Weak"); + else if (strength < 50) + str = C_("Signal strength", "Ok"); + else if (strength < 80) + str = C_("Signal strength", "Good"); + else + str = C_("Signal strength", "Excellent"); + panel_set_device_widget_details (device_wifi->priv->builder, + "strength", + str); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "label_device")); + gtk_label_set_label (GTK_LABEL (widget), + priv->selected_ssid_title ? priv->selected_ssid_title : panel_device_to_localized_string (nm_device)); + + /* only disconnect when connection active */ + if (ap == active_ap) { + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_disconnect1")); + gtk_widget_set_sensitive (widget, state == NM_DEVICE_STATE_ACTIVATED); + gtk_widget_show (widget); + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_connect1")); + gtk_widget_hide (widget); + } else { + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_disconnect1")); + gtk_widget_hide (widget); + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_connect1")); + gtk_widget_show (widget); + gtk_widget_set_sensitive (widget, ap != NULL); + } + + /* device MAC */ + if (ap != active_ap) + str = NULL; + else + str = nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (nm_device)); + panel_set_device_widget_details (priv->builder, "mac", str); + + /* set IP entries */ + if (ap != active_ap) + panel_unset_device_widgets (priv->builder); + else + panel_set_device_widgets (priv->builder, nm_device); + + if (ap != active_ap) + update_last_used (device_wifi); + else + panel_set_device_widget_details (priv->builder, "last_used", NULL); + + /* update list of APs */ + device_wifi_refresh_aps (device_wifi); + device_wifi_refresh_saved_connections (device_wifi); +} + +static void +device_wifi_refresh (NetObject *object) +{ + NetDeviceWifi *device_wifi = NET_DEVICE_WIFI (object); + nm_device_wifi_refresh_ui (device_wifi); +} + +static void +device_off_toggled (GtkSwitch *sw, + GParamSpec *pspec, + NetDeviceWifi *device_wifi) +{ + NMClient *client; + gboolean active; + + if (device_wifi->priv->updating_device) + return; + + client = net_object_get_client (NET_OBJECT (device_wifi)); + active = gtk_switch_get_active (sw); + nm_client_wireless_set_enabled (client, active); +} + + +static gboolean +find_connection_id_in_store (GtkTreeModel *model, + GtkTreeIter *iter, + const gchar *connection_id) +{ + gboolean found; + gchar *id; + + found = gtk_tree_model_get_iter_first (model, iter); + while (found) { + gtk_tree_model_get (model, iter, + COLUMN_CONNECTION_ID, &id, + -1); + if (g_strcmp0 (connection_id, id) == 0) { + g_free (id); + return TRUE; + } + g_free (id); + found = gtk_tree_model_iter_next (model, iter); + } + return FALSE; +} + +static void +forget_network_connection_delete_cb (NMRemoteConnection *connection, + GError *error, + gpointer user_data) +{ + gboolean ret; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeView *treeview; + + NetDeviceWifi *device_wifi = NET_DEVICE_WIFI (user_data); + + if (error != NULL) { + g_warning ("failed to delete connection %s: %s", + nm_object_get_path (NM_OBJECT (connection)), + error->message); + return; + } + + /* remove the entry from the list */ + treeview = GTK_TREE_VIEW (gtk_builder_get_object (device_wifi->priv->builder, + "treeview_list")); + model = gtk_tree_view_get_model (treeview); + ret = find_connection_id_in_store (model, &iter, + device_wifi->priv->selected_connection_id); + if (ret) + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + show_wifi_list (device_wifi); +} + +static void +forget_network_response_cb (GtkWidget *dialog, + gint response, + NetDeviceWifi *device_wifi) +{ + NMRemoteConnection *connection; + NMRemoteSettings *remote_settings; + + if (response != GTK_RESPONSE_OK) + goto out; + + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + connection = nm_remote_settings_get_connection_by_path (remote_settings, device_wifi->priv->selected_connection_id); + if (connection == NULL) { + g_warning ("failed to get remote connection"); + goto out; + } + + /* delete the connection */ + g_debug ("deleting %s", device_wifi->priv->selected_connection_id); + nm_remote_connection_delete (connection, + forget_network_connection_delete_cb, + device_wifi); +out: + gtk_widget_destroy (dialog); +} + +static void +disconnect_button_clicked_cb (GtkButton *button, NetDeviceWifi *device_wifi) +{ + NMDevice *device; + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + if (device == NULL) + return; + nm_device_disconnect (device, NULL, NULL); +} + +static void activate_connection (NetDeviceWifi *device, const gchar *id); + +static void +connect_button_clicked_cb (GtkButton *button, NetDeviceWifi *device_wifi) +{ + if (device_wifi->priv->selected_connection_id) + activate_connection (device_wifi, device_wifi->priv->selected_connection_id); +} + +static void +forget_button_clicked_cb (GtkButton *button, NetDeviceWifi *device_wifi) +{ + gchar *ssid_pretty = NULL; + gchar *warning = NULL; + GtkWidget *dialog; + GtkWidget *window; + CcNetworkPanel *panel; + + ssid_pretty = g_strdup_printf ("%s", device_wifi->priv->selected_ssid_title); + warning = g_strdup_printf (_("Network details for %s including password and any custom configuration will be lost."), ssid_pretty); + panel = net_object_get_panel (NET_OBJECT (device_wifi)); + window = gtk_widget_get_toplevel (GTK_WIDGET (panel)); + dialog = gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_NONE, + NULL); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), warning); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("Forget"), GTK_RESPONSE_OK, + NULL); + g_signal_connect (dialog, "response", + G_CALLBACK (forget_network_response_cb), device_wifi); + gtk_window_present (GTK_WINDOW (dialog)); + + g_free (ssid_pretty); + g_free (warning); +} + + +static void +connect_to_hidden_network (NetDeviceWifi *device_wifi) +{ + NMRemoteSettings *remote_settings; + NMClient *client; + CcNetworkPanel *panel; + + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + client = net_object_get_client (NET_OBJECT (device_wifi)); + panel = net_object_get_panel (NET_OBJECT (device_wifi)); + cc_network_panel_connect_to_hidden_network (panel, client, remote_settings); +} + +static void +connection_add_activate_cb (NMClient *client, + NMActiveConnection *connection, + const char *path, + GError *error, + gpointer user_data) +{ + NetDeviceWifi *device_wifi = user_data; + + if (connection == NULL) { + /* failed to activate */ + g_debug ("Failed to add and activate connection '%d': %s", + error->code, + error->message); + nm_device_wifi_refresh_ui (device_wifi); + } +} + +static void +connection_activate_cb (NMClient *client, + NMActiveConnection *connection, + GError *error, + gpointer user_data) +{ + NetDeviceWifi *device_wifi = user_data; + + if (connection == NULL) { + /* failed to activate */ + g_debug ("Failed to activate connection '%d': %s", + error->code, + error->message); + nm_device_wifi_refresh_ui (device_wifi); + } +} + +static void +activate_connection (NetDeviceWifi *device_wifi, + const gchar *connection_id) +{ + NMDevice *device; + NMClient *client; + NMRemoteSettings *settings; + NMRemoteConnection *connection; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + client = net_object_get_client (NET_OBJECT (device_wifi)); + settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + connection = nm_remote_settings_get_connection_by_path (settings, connection_id); + nm_client_activate_connection (client, + NM_CONNECTION (connection), + device, NULL, + connection_activate_cb, device_wifi); +} + +static gboolean +is_8021x (NMDevice *device, + const char *ap_object_path) +{ + NM80211ApSecurityFlags wpa_flags, rsn_flags; + NMAccessPoint *ap; + + ap = nm_device_wifi_get_access_point_by_path (NM_DEVICE_WIFI (device), + ap_object_path); + if (!ap) + return FALSE; + + rsn_flags = nm_access_point_get_rsn_flags (ap); + if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + return TRUE; + + wpa_flags = nm_access_point_get_wpa_flags (ap); + if (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + return TRUE; + return FALSE; +} + +static void +wireless_try_to_connect (NetDeviceWifi *device_wifi, + const gchar *ssid_target, + const gchar *ap_object_path) +{ + const GByteArray *ssid; + const gchar *ssid_tmp; + GSList *list, *l; + GSList *filtered; + NMConnection *connection_activate = NULL; + NMDevice *device; + NMSettingWireless *setting_wireless; + NMRemoteSettings *remote_settings; + NMClient *client; + + if (device_wifi->priv->updating_device) + goto out; + + if (ap_object_path == NULL || ap_object_path[0] == 0) + goto out; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + if (device == NULL) + goto out; + + g_debug ("try to connect to WIFI network %s [%s]", + ssid_target, ap_object_path); + + /* look for an existing connection we can use */ + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + list = nm_remote_settings_list_connections (remote_settings); + g_debug ("%i existing remote connections available", g_slist_length (list)); + filtered = nm_device_filter_connections (device, list); + g_debug ("%i suitable remote connections to check", g_slist_length (filtered)); + for (l = filtered; l; l = g_slist_next (l)) { + NMConnection *connection; + + connection = NM_CONNECTION (l->data); + setting_wireless = nm_connection_get_setting_wireless (connection); + if (!NM_IS_SETTING_WIRELESS (setting_wireless)) + continue; + ssid = nm_setting_wireless_get_ssid (setting_wireless); + if (ssid == NULL) + continue; + ssid_tmp = nm_utils_escape_ssid (ssid->data, ssid->len); + if (g_strcmp0 (ssid_target, ssid_tmp) == 0) { + g_debug ("we found an existing connection %s to activate!", + nm_connection_get_id (connection)); + connection_activate = connection; + break; + } + } + + g_slist_free (list); + g_slist_free (filtered); + + /* activate the connection */ + client = net_object_get_client (NET_OBJECT (device_wifi)); + if (connection_activate != NULL) { + nm_client_activate_connection (client, + connection_activate, + device, NULL, + connection_activate_cb, device_wifi); + goto out; + } + + /* create one, as it's missing */ + g_debug ("no existing connection found for %s, creating", ssid_target); + + if (!is_8021x (device, ap_object_path)) { + g_debug ("no existing connection found for %s, creating and activating one", ssid_target); + nm_client_add_and_activate_connection (client, + NULL, + device, ap_object_path, + connection_add_activate_cb, device_wifi); + } else { + CcNetworkPanel *panel; + GPtrArray *array; + + g_debug ("no existing connection found for %s, creating", ssid_target); + array = g_ptr_array_new (); + g_ptr_array_add (array, "connect-8021x-wifi"); + g_ptr_array_add (array, (gpointer) nm_object_get_path (NM_OBJECT (device))); + g_ptr_array_add (array, (gpointer) ap_object_path); + g_ptr_array_add (array, NULL); + + panel = net_object_get_panel (NET_OBJECT (device_wifi)); + g_object_set (G_OBJECT (panel), "argv", array->pdata, NULL); + + g_ptr_array_free (array, FALSE); + } +out: + return; +} + +static gint +wireless_ap_model_sort_cb (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gboolean active_a; + gboolean active_b; + gboolean ap_a; + gboolean ap_b; + gchar *str_a; + gchar *str_b; + gint retval; + gint strength_a; + gint strength_b; + + gtk_tree_model_get (model, a, + COLUMN_SORT, &str_a, + COLUMN_STRENGTH, &strength_a, + COLUMN_ACTIVE, &active_a, + COLUMN_AP_IN_RANGE, &ap_a, + -1); + gtk_tree_model_get (model, b, + COLUMN_SORT, &str_b, + COLUMN_STRENGTH, &strength_b, + COLUMN_ACTIVE, &active_b, + COLUMN_AP_IN_RANGE, &ap_b, + -1); + + /* active entry first */ + if (active_a) { + retval = -1; + goto out; + } + + if (active_b) { + retval = 1; + goto out; + } + + /* aps before connections */ + if (ap_a && !ap_b) { + retval = -1; + goto out; + } + if (!ap_a && ap_b) { + retval = 1; + goto out; + } + + /* case sensitive search like before */ + retval = strength_b - strength_a; +out: + g_free (str_a); + g_free (str_b); + + return retval; +} + +static GByteArray * +ssid_to_byte_array (const gchar *ssid) +{ + guint32 len; + GByteArray *ba; + + len = strlen (ssid); + ba = g_byte_array_sized_new (len); + g_byte_array_append (ba, (guchar *)ssid, len); + + return ba; +} + +static gchar * +get_hostname (void) +{ + GDBusConnection *bus; + GVariant *res; + GVariant *inner; + gchar *str; + GError *error; + + error = NULL; + bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (error != NULL) { + g_warning ("Failed to get system bus connection: %s", error->message); + g_error_free (error); + + return NULL; + } + res = g_dbus_connection_call_sync (bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + "org.freedesktop.hostname1", + "PrettyHostname"), + (GVariantType*)"(v)", + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + g_object_unref (bus); + + if (error != NULL) { + g_warning ("Getting pretty hostname failed: %s", error->message); + g_error_free (error); + } + + str = NULL; + + if (res != NULL) { + g_variant_get (res, "(v)", &inner); + str = g_variant_dup_string (inner, NULL); + g_variant_unref (res); + } + + if (str == NULL || *str == '\0') { + str = g_strdup (g_get_host_name ()); + } + + if (str == NULL || *str == '\0') { + str = g_strdup ("GNOME"); + } + + return str; +} + +static GByteArray * +generate_ssid_for_hotspot (NetDeviceWifi *device_wifi) +{ + GByteArray *ssid_array; + gchar *ssid; + + ssid = get_hostname (); + ssid_array = ssid_to_byte_array (ssid); + g_free (ssid); + + return ssid_array; +} + +static gchar * +generate_wep_key (NetDeviceWifi *device_wifi) +{ + gchar key[11]; + gint i; + const gchar *hexdigits = "0123456789abcdef"; + + /* generate a 10-digit hex WEP key */ + for (i = 0; i < 10; i++) { + gint digit; + digit = g_random_int_range (0, 16); + key[i] = hexdigits[digit]; + } + key[10] = 0; + + return g_strdup (key); +} + +static gboolean +is_hotspot_connection (NMConnection *connection) +{ + NMSettingConnection *sc; + NMSettingWireless *sw; + NMSettingIP4Config *sip; + + sc = nm_connection_get_setting_connection (connection); + if (g_strcmp0 (nm_setting_connection_get_connection_type (sc), "802-11-wireless") != 0) { + return FALSE; + } + sw = nm_connection_get_setting_wireless (connection); + if (g_strcmp0 (nm_setting_wireless_get_mode (sw), "adhoc") != 0) { + return FALSE; + } + if (g_strcmp0 (nm_setting_wireless_get_security (sw), "802-11-wireless-security") != 0) { + return FALSE; + } + sip = nm_connection_get_setting_ip4_config (connection); + if (g_strcmp0 (nm_setting_ip4_config_get_method (sip), "shared") != 0) { + return FALSE; + } + + return TRUE; +} + +static void +show_hotspot_ui (NetDeviceWifi *device_wifi) +{ + GtkWidget *widget; + GtkSwitch *sw; + + /* show hotspot tab */ + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "notebook_view")); + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 3); + + /* force switch to on as this succeeded */ + sw = GTK_SWITCH (gtk_builder_get_object (device_wifi->priv->builder, + "switch_hotspot_off")); + device_wifi->priv->updating_device = TRUE; + gtk_switch_set_active (sw, TRUE); + device_wifi->priv->updating_device = FALSE; +} + +static void +activate_cb (NMClient *client, + NMActiveConnection *connection, + GError *error, + NetDeviceWifi *device_wifi) +{ + if (error != NULL) { + g_warning ("Failed to add new connection: (%d) %s", + error->code, + error->message); + return; + } + + /* show hotspot tab */ + nm_device_wifi_refresh_ui (device_wifi); + show_hotspot_ui (device_wifi); +} + +static void +activate_new_cb (NMClient *client, + NMActiveConnection *connection, + const gchar *path, + GError *error, + NetDeviceWifi *device_wifi) +{ + activate_cb (client, connection, error, device_wifi); +} + +static void +start_shared_connection (NetDeviceWifi *device_wifi) +{ + NMConnection *c; + NMConnection *tmp; + NMSettingConnection *sc; + NMSettingWireless *sw; + NMSettingIP4Config *sip; + NMSettingWirelessSecurity *sws; + NMDevice *device; + GByteArray *ssid_array; + gchar *wep_key; + const gchar *str_mac; + struct ether_addr *bin_mac; + GSList *connections; + GSList *filtered; + GSList *l; + NMClient *client; + NMRemoteSettings *remote_settings; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + g_assert (nm_device_get_device_type (device) == NM_DEVICE_TYPE_WIFI); + + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + connections = nm_remote_settings_list_connections (remote_settings); + filtered = nm_device_filter_connections (device, connections); + g_slist_free (connections); + c = NULL; + for (l = filtered; l; l = l->next) { + tmp = l->data; + if (is_hotspot_connection (tmp)) { + c = tmp; + break; + } + } + g_slist_free (filtered); + + client = net_object_get_client (NET_OBJECT (device_wifi)); + if (c != NULL) { + g_debug ("activate existing hotspot connection\n"); + nm_client_activate_connection (client, + c, + device, + NULL, + (NMClientActivateFn)activate_cb, + device_wifi); + return; + } + + g_debug ("create new hotspot connection\n"); + c = nm_connection_new (); + + sc = (NMSettingConnection *)nm_setting_connection_new (); + g_object_set (sc, + "type", "802-11-wireless", + "id", "Hotspot", + "autoconnect", FALSE, + NULL); + nm_connection_add_setting (c, (NMSetting *)sc); + + sw = (NMSettingWireless *)nm_setting_wireless_new (); + g_object_set (sw, + "mode", "adhoc", + "security", "802-11-wireless-security", + NULL); + + str_mac = nm_device_wifi_get_permanent_hw_address (NM_DEVICE_WIFI (device)); + bin_mac = ether_aton (str_mac); + if (bin_mac) { + GByteArray *hw_address; + + hw_address = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (hw_address, bin_mac->ether_addr_octet, ETH_ALEN); + g_object_set (sw, + "mac-address", hw_address, + NULL); + g_byte_array_unref (hw_address); + } + nm_connection_add_setting (c, (NMSetting *)sw); + + sip = (NMSettingIP4Config*) nm_setting_ip4_config_new (); + g_object_set (sip, "method", "shared", NULL); + nm_connection_add_setting (c, (NMSetting *)sip); + + ssid_array = generate_ssid_for_hotspot (device_wifi); + g_object_set (sw, + "ssid", ssid_array, + NULL); + g_byte_array_unref (ssid_array); + + sws = (NMSettingWirelessSecurity*) nm_setting_wireless_security_new (); + wep_key = generate_wep_key (device_wifi); + g_object_set (sws, + "key-mgmt", "none", + "wep-key0", wep_key, + "wep-key-type", NM_WEP_KEY_TYPE_KEY, + NULL); + g_free (wep_key); + nm_connection_add_setting (c, (NMSetting *)sws); + + nm_client_add_and_activate_connection (client, + c, + device, + NULL, + (NMClientAddActivateFn)activate_new_cb, + device_wifi); + + g_object_unref (c); +} + +static void +start_hotspot_response_cb (GtkWidget *dialog, gint response, NetDeviceWifi *device_wifi) +{ + if (response == GTK_RESPONSE_OK) { + start_shared_connection (device_wifi); + } + gtk_widget_hide (dialog); +} + +static void +start_hotspot (GtkButton *button, NetDeviceWifi *device_wifi) +{ + NMDevice *device; + const GPtrArray *connections; + gchar *active_ssid; + NMClient *client; + GtkWidget *dialog; + GtkWidget *window; + GtkWidget *widget; + GString *str; + + active_ssid = NULL; + + client = net_object_get_client (NET_OBJECT (device_wifi)); + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + connections = nm_client_get_active_connections (client); + if (connections) { + gint i; + for (i = 0; i < connections->len; i++) { + NMActiveConnection *c; + const GPtrArray *devices; + c = (NMActiveConnection *)connections->pdata[i]; + devices = nm_active_connection_get_devices (c); + if (devices && devices->pdata[0] == device) { + NMAccessPoint *ap; + ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device)); + active_ssid = nm_utils_ssid_to_utf8 (nm_access_point_get_ssid (ap)); + break; + } + } + } + + window = gtk_widget_get_toplevel (GTK_WIDGET (button)); + + dialog = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "hotspot-dialog")); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window)); + + str = g_string_new (_("If you have a connection to the Internet other than wireless, you can use it to share your internet connection with others.")); + g_string_append (str, "\n\n"); + + if (active_ssid) { + g_string_append_printf (str, _("Switching on the wireless hotspot will disconnect you from %s."), active_ssid); + g_string_append (str, " "); + } + + g_string_append (str, _("It is not possible to access the internet through your wireless while the hotspot is active.")); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "hotspot-dialog-content")); + gtk_label_set_markup (GTK_LABEL (widget), str->str); + g_string_free (str, TRUE); + + g_signal_connect (dialog, "response", + G_CALLBACK (start_hotspot_response_cb), device_wifi); + gtk_window_present (GTK_WINDOW (dialog)); + g_free (active_ssid); +} + +static void +stop_shared_connection (NetDeviceWifi *device_wifi) +{ + const GPtrArray *connections; + const GPtrArray *devices; + NMDevice *device; + gint i; + NMActiveConnection *c; + NMClient *client; + + device = net_device_get_nm_device (NET_DEVICE (device_wifi)); + client = net_object_get_client (NET_OBJECT (device_wifi)); + connections = nm_client_get_active_connections (client); + for (i = 0; i < connections->len; i++) { + c = (NMActiveConnection *)connections->pdata[i]; + + devices = nm_active_connection_get_devices (c); + if (devices && devices->pdata[0] == device) { + nm_client_deactivate_connection (client, c); + break; + } + } + + nm_device_wifi_refresh_ui (device_wifi); + show_wifi_list (device_wifi); +} + +static void +stop_hotspot_response_cb (GtkWidget *dialog, gint response, NetDeviceWifi *device_wifi) +{ + if (response == GTK_RESPONSE_OK) { + stop_shared_connection (device_wifi); + } + gtk_widget_destroy (dialog); +} + +static void +switch_hotspot_changed_cb (GtkSwitch *sw, + GParamSpec *pspec, + NetDeviceWifi *device_wifi) +{ + GtkWidget *dialog; + GtkWidget *window; + CcNetworkPanel *panel; + + if (device_wifi->priv->updating_device) + return; + + panel = net_object_get_panel (NET_OBJECT (device_wifi)); + window = gtk_widget_get_toplevel (GTK_WIDGET (panel)); + dialog = gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_NONE, + _("Stop hotspot and disconnect any users?")); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("_Stop Hotspot"), GTK_RESPONSE_OK, + NULL); + g_signal_connect (dialog, "response", + G_CALLBACK (stop_hotspot_response_cb), device_wifi); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +connect_wifi_network (NetDeviceWifi *device_wifi, + GtkTreeView *tv, + GtkTreePath *path) +{ + gboolean ap_in_range; + gchar *ap_object_path; + gchar *ssid; + gchar *connection_id; + GtkTreeIter iter; + GtkTreeModel *model; + NM80211Mode mode; + + model = gtk_tree_view_get_model (tv); + gtk_tree_model_get_iter (model, &iter, path); + + gtk_tree_model_get (model, &iter, + COLUMN_ACCESS_POINT_ID, &ap_object_path, + COLUMN_CONNECTION_ID, &connection_id, + COLUMN_TITLE, &ssid, + COLUMN_AP_IN_RANGE, &ap_in_range, + COLUMN_MODE, &mode, + -1); + if (ap_in_range) { + if (connection_id) + activate_connection (device_wifi, connection_id); + else + wireless_try_to_connect (device_wifi, ssid, ap_object_path); + } else { + g_warning ("can't connect"); + } + + g_free (ap_object_path); + g_free (connection_id); + g_free (ssid); +} + +static void +show_wifi_details (NetDeviceWifi *device_wifi, + GtkTreeView *tv, + GtkTreePath *path) +{ + GtkWidget *widget; + gboolean ret; + gboolean in_range; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *path_str; + + model = gtk_tree_view_get_model (tv); + path_str = gtk_tree_path_to_string (path); + ret = gtk_tree_model_get_iter_from_string (model, &iter, path_str); + if (!ret) + goto out; + + /* get parameters about the selected connection */ + g_free (device_wifi->priv->selected_connection_id); + g_free (device_wifi->priv->selected_ssid_title); + gtk_tree_model_get (model, &iter, + COLUMN_ACCESS_POINT_ID, &device_wifi->priv->selected_ap_id, + COLUMN_CONNECTION_ID, &device_wifi->priv->selected_connection_id, + COLUMN_TITLE, &device_wifi->priv->selected_ssid_title, + COLUMN_AP_IN_RANGE, &in_range, + -1); + g_debug ("ssid = %s, in-range = %i", + device_wifi->priv->selected_ssid_title, in_range); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "notebook_view")); + + nm_device_wifi_refresh_ui (device_wifi); + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1); + +out: + g_free (path_str); +} + +static void +show_wifi_list (NetDeviceWifi *device_wifi) +{ + GtkWidget *widget; + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, "notebook_view")); + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0); +} + +static gboolean +arrow_visible (GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean active; + gboolean ap_is_saved; + gboolean ret; + gchar *sort; + + gtk_tree_model_get (model, iter, + COLUMN_ACTIVE, &active, + COLUMN_AP_IS_SAVED, &ap_is_saved, + COLUMN_SORT, &sort, + -1); + + if (active || ap_is_saved) + ret = TRUE; + else + ret = FALSE; + + g_free (sort); + + return ret; +} + +static void +set_arrow_image (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + NetDeviceWifi *device = user_data; + const gchar *icon; + + if (arrow_visible (model, iter)) { + GtkWidget *widget; + + widget = GTK_WIDGET (gtk_builder_get_object (device->priv->builder, + "treeview_list")); + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + icon = "go-previous"; + else + icon = "go-next"; + } + else { + icon = ""; + } + + g_object_set (cell, "icon-name", icon, NULL); +} + +static void +edit_connection (GtkButton *button, NetDeviceWifi *device_wifi) +{ + net_object_edit (NET_OBJECT (device_wifi)); +} + +static void +remote_settings_read_cb (NMRemoteSettings *remote_settings, + NetDeviceWifi *device_wifi) +{ + gboolean is_hotspot; + + device_wifi_refresh_saved_connections (device_wifi); + + /* go straight to the hotspot UI */ + is_hotspot = device_is_hotspot (device_wifi); + if (is_hotspot) { + nm_device_wifi_refresh_hotspot (device_wifi); + show_hotspot_ui (device_wifi); + } +} + +static gboolean +separator_visible (GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean active; + gboolean ap_is_saved; + gboolean ap_in_range; + gchar *sort; + gboolean ret; + + gtk_tree_model_get (model, iter, + COLUMN_ACTIVE, &active, + COLUMN_AP_IS_SAVED, &ap_is_saved, + COLUMN_AP_IN_RANGE, &ap_in_range, + COLUMN_SORT, &sort, + -1); + + if (!active && ap_is_saved && ap_in_range) + ret = TRUE; + else + ret = FALSE; + + g_free (sort); + + return ret; + +} + +static void +set_draw_separator (GtkCellLayout *layout, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + gboolean draw; + + draw = separator_visible (model, iter); + + g_object_set (cell, "draw", draw, NULL); +} + +static void +switch_page_cb (GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + NetDeviceWifi *device_wifi) +{ + GtkWidget *widget; + + if (page_num == 1) { + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_back1")); + gtk_widget_grab_focus (widget); + } +} + +static void +net_device_wifi_constructed (GObject *object) +{ + NetDeviceWifi *device_wifi = NET_DEVICE_WIFI (object); + NMClient *client; + NMRemoteSettings *remote_settings; + NMClientPermissionResult perm; + GtkWidget *widget; + + G_OBJECT_CLASS (net_device_wifi_parent_class)->constructed (object); + + client = net_object_get_client (NET_OBJECT (device_wifi)); + g_signal_connect (client, "notify::wireless-enabled", + G_CALLBACK (wireless_enabled_toggled), device_wifi); + + /* only show the button if the user can create a hotspot */ + perm = nm_client_get_permission_result (client, NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN); + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "start_hotspot_button")); + gtk_widget_set_sensitive (widget, perm == NM_CLIENT_PERMISSION_RESULT_YES || + perm == NM_CLIENT_PERMISSION_RESULT_AUTH); + + remote_settings = net_object_get_remote_settings (NET_OBJECT (device_wifi)); + g_signal_connect (remote_settings, "connections-read", + G_CALLBACK (remote_settings_read_cb), device_wifi); + + nm_device_wifi_refresh_ui (device_wifi); +} + +static void +net_device_wifi_finalize (GObject *object) +{ + NetDeviceWifi *device_wifi = NET_DEVICE_WIFI (object); + NetDeviceWifiPrivate *priv = device_wifi->priv; + + g_object_unref (priv->builder); + g_free (priv->selected_ssid_title); + g_free (priv->selected_connection_id); + g_free (priv->selected_ap_id); + + G_OBJECT_CLASS (net_device_wifi_parent_class)->finalize (object); +} + +static void +device_wifi_edit (NetObject *object) +{ + const gchar *uuid; + gchar *cmdline; + GError *error = NULL; + NetDeviceWifi *device = NET_DEVICE_WIFI (object); + NMRemoteSettings *settings; + NMRemoteConnection *connection; + + settings = net_object_get_remote_settings (object); + connection = nm_remote_settings_get_connection_by_path (settings, device->priv->selected_connection_id); + if (connection == NULL) { + g_warning ("failed to get remote connection"); + return; + } + uuid = nm_connection_get_uuid (NM_CONNECTION (connection)); + cmdline = g_strdup_printf ("nm-connection-editor --edit %s", uuid); + g_debug ("Launching '%s'\n", cmdline); + if (!g_spawn_command_line_async (cmdline, &error)) { + g_warning ("Failed to launch nm-connection-editor: %s", error->message); + g_error_free (error); + } + g_free (cmdline); +} + +static void +net_device_wifi_class_init (NetDeviceWifiClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NetObjectClass *parent_class = NET_OBJECT_CLASS (klass); + + object_class->finalize = net_device_wifi_finalize; + object_class->constructed = net_device_wifi_constructed; + parent_class->add_to_notebook = device_wifi_proxy_add_to_notebook; + parent_class->refresh = device_wifi_refresh; + parent_class->edit = device_wifi_edit; + + g_type_class_add_private (klass, sizeof (NetDeviceWifiPrivate)); +} + +static void +activate_ssid_cb (PanelCellRendererText *cell, + const gchar *path, + NetDeviceWifi *device_wifi) +{ + GtkTreeView *tv; + GtkTreePath *tpath; + + g_debug ("activate ssid!\n"); + + tv = GTK_TREE_VIEW (gtk_builder_get_object (device_wifi->priv->builder, + "treeview_list")); + tpath = gtk_tree_path_new_from_string (path); + + connect_wifi_network (device_wifi, tv, tpath); + + gtk_tree_path_free (tpath); +} + +static void +activate_arrow_cb (PanelCellRendererText *cell, + const gchar *path, + NetDeviceWifi *device_wifi) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreePath *tpath; + GtkTreeIter iter; + + g_debug ("activate arrow!\n"); + + tv = GTK_TREE_VIEW (gtk_builder_get_object (device_wifi->priv->builder, + "treeview_list")); + model = gtk_tree_view_get_model (tv); + tpath = gtk_tree_path_new_from_string (path); + gtk_tree_model_get_iter (model, &iter, tpath); + + if (arrow_visible (model, &iter)) + show_wifi_details (device_wifi, tv, tpath); + gtk_tree_path_free (tpath); +} + +static void +net_device_wifi_init (NetDeviceWifi *device_wifi) +{ + GError *error = NULL; + GtkWidget *widget; + GtkCellRenderer *renderer1; + GtkCellRenderer *renderer2; + GtkCellRenderer *renderer3; + GtkCellRenderer *renderer4; + GtkCellRenderer *renderer5; + GtkCellRenderer *renderer6; + GtkCellRenderer *renderer7; + GtkCellRenderer *renderer8; + GtkTreeSortable *sortable; + GtkTreeViewColumn *column; + GtkCellArea *area; + + device_wifi->priv = NET_DEVICE_WIFI_GET_PRIVATE (device_wifi); + + device_wifi->priv->builder = gtk_builder_new (); + gtk_builder_add_from_file (device_wifi->priv->builder, + GNOMECC_UI_DIR "/network-wifi.ui", + &error); + if (error != NULL) { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + /* setup wifi views */ + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "device_off_switch")); + g_signal_connect (widget, "notify::active", + G_CALLBACK (device_off_toggled), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_options1")); + g_signal_connect (widget, "clicked", + G_CALLBACK (edit_connection), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_forget1")); + g_signal_connect (widget, "clicked", + G_CALLBACK (forget_button_clicked_cb), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_disconnect1")); + g_signal_connect (widget, "clicked", + G_CALLBACK (disconnect_button_clicked_cb), device_wifi); + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_connect1")); + g_signal_connect (widget, "clicked", + G_CALLBACK (connect_button_clicked_cb), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "treeview_list")); + + /* sort networks in drop down */ + sortable = GTK_TREE_SORTABLE (gtk_builder_get_object (device_wifi->priv->builder, + "liststore_network")); + gtk_tree_sortable_set_sort_column_id (sortable, + COLUMN_SORT, + GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (sortable, + COLUMN_SORT, + wireless_ap_model_sort_cb, + device_wifi, + NULL); + + + column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (device_wifi->priv->builder, + "treeview_list_column")); + area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)); + + renderer1 = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer1, FALSE); + g_object_set (renderer1, + "follow-state", TRUE, + "icon-name", "object-select-symbolic", + "xpad", 6, + "ypad", 6, + NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer1, + "visible", COLUMN_ACTIVE, + NULL); + gtk_cell_area_cell_set (area, renderer1, "align", TRUE, NULL); + + renderer2 = panel_cell_renderer_text_new (); + g_object_set (renderer2, + "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer2, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer2, + "markup", COLUMN_TITLE, + NULL); + gtk_cell_area_cell_set (area, renderer2, + "align", TRUE, + "expand", TRUE, + NULL); + g_signal_connect (renderer2, "activate", + G_CALLBACK (activate_ssid_cb), device_wifi); + + renderer3 = panel_cell_renderer_mode_new (); + gtk_cell_renderer_set_padding (renderer3, 4, 0); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), + renderer3, + FALSE); + g_object_set (renderer3, "follow-state", TRUE, NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer3, + "ap-mode", COLUMN_MODE, + NULL); + + renderer4 = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer4, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer4, + "visible", COLUMN_AP_OUT_OF_RANGE, + NULL); + g_object_set (renderer4, + "text", _("Out of range"), + "mode", GTK_CELL_RENDERER_MODE_INERT, + "xalign", 1.0, + NULL); + + renderer5 = panel_cell_renderer_signal_new (); + gtk_cell_renderer_set_padding (renderer5, 4, 0); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), + renderer5, + FALSE); + g_object_set (renderer5, "follow-state", TRUE, NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer5, + "signal", COLUMN_STRENGTH, + "visible", COLUMN_AP_IN_RANGE, + NULL); + + renderer6 = panel_cell_renderer_security_new (); + gtk_cell_renderer_set_padding (renderer6, 4, 0); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), + renderer6, + FALSE); + g_object_set (renderer6, "follow-state", TRUE, NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer6, + "security", COLUMN_SECURITY, + "visible", COLUMN_AP_IN_RANGE, + NULL); + + renderer7 = panel_cell_renderer_separator_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer7, FALSE); + g_object_set (renderer7, + "visible", TRUE, + "sensitive", FALSE, + "draw", TRUE, + NULL); + gtk_cell_renderer_set_fixed_size (renderer7, 1, -1); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer7, + set_draw_separator, device_wifi, NULL); + + renderer8 = panel_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer8, FALSE); + g_object_set (renderer8, + "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, + "follow-state", TRUE, + "visible", TRUE, + "xpad", 6, + "ypad", 6, + NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer8, + set_arrow_image, device_wifi, NULL); + g_signal_connect (renderer8, "activate", + G_CALLBACK (activate_arrow_cb), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "button_back1")); + g_signal_connect_swapped (widget, "clicked", + G_CALLBACK (show_wifi_list), device_wifi); + + /* draw focus around everything but the arrow */ + gtk_cell_area_add_focus_sibling (area, renderer2, renderer1); + gtk_cell_area_add_focus_sibling (area, renderer2, renderer3); + gtk_cell_area_add_focus_sibling (area, renderer2, renderer4); + gtk_cell_area_add_focus_sibling (area, renderer2, renderer5); + gtk_cell_area_add_focus_sibling (area, renderer2, renderer6); + gtk_cell_area_add_focus_sibling (area, renderer2, renderer7); + + /* setup view */ + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "notebook_view")); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); + gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0); + g_signal_connect_after (widget, "switch-page", + G_CALLBACK (switch_page_cb), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "start_hotspot_button")); + g_signal_connect (widget, "clicked", + G_CALLBACK (start_hotspot), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "connect_hidden_button")); + g_signal_connect_swapped (widget, "clicked", + G_CALLBACK (connect_to_hidden_network), device_wifi); + + widget = GTK_WIDGET (gtk_builder_get_object (device_wifi->priv->builder, + "switch_hotspot_off")); + g_signal_connect (widget, "notify::active", + G_CALLBACK (switch_hotspot_changed_cb), device_wifi); +} diff -Nru gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/configure.ac gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/configure.ac --- gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/configure.ac 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/configure.ac 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,551 @@ +m4_define([gnome_control_center_version], 3.6.3) +AC_INIT([gnome-control-center], [gnome_control_center_version], + [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-control-center]) + +AC_CONFIG_SRCDIR([shell]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar check-news]) +AM_MAINTAINER_MODE([enable]) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# Check for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_HEADER_STDC + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# .so version for libgnome-control-center +LIBGNOMECONTROLCENTER_CURRENT=1 +LIBGNOMECONTROLCENTER_REVISION=0 +LIBGNOMECONTROLCENTER_AGE=0 +AC_SUBST(LIBGNOMECONTROLCENTER_CURRENT) +AC_SUBST(LIBGNOMECONTROLCENTER_REVISION) +AC_SUBST(LIBGNOMECONTROLCENTER_AGE) + +# Internationalization support + +IT_PROG_INTLTOOL([0.40.1]) + +GETTEXT_PACKAGE=gnome-control-center-2.0 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) + +GNOME_DEBUG_CHECK +GNOME_COMPILE_WARNINGS([maximum]) + +AC_PATH_XTRA +x_libs="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" + +AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) + +AC_ARG_ENABLE(documentation, + AC_HELP_STRING([--enable-documentation], + [build documentation]),, + enable_documentation=yes) +if test x$enable_documentation = xyes; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test x$XSLTPROC = x; then + AC_MSG_ERROR([xsltproc is required to build documentation]) + fi +fi +AM_CONDITIONAL(BUILD_DOCUMENTATION, test x$enable_documentation = xyes) + +dnl Region panel +savecppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $X_CFLAGS" +AC_CHECK_HEADERS([X11/Xlib.h]) +AC_CHECK_LIB(Xxf86misc, XF86MiscQueryExtension, [ + AC_CHECK_HEADERS([X11/extensions/xf86misc.h], [XF86MISC_LIBS="-lXxf86misc"],[], +[#if HAVE_X11_XLIB_H +#include +#endif +])]) +AC_SUBST(XF86MISC_LIBS) +AC_CHECK_HEADERS(X11/extensions/XKB.h) +CPPFLAGS=$savecppflags + +AC_CHECK_LIB(m, floor) + +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [with_systemd=$enableval], + [with_systemd=no]) +if test "$with_systemd" = "yes" ; then + SYSTEMD=libsystemd-login + AC_DEFINE(HAVE_SYSTEMD, 1, [Define to 1 if systemd is available]) +else + SYSTEMD= +fi + +# IBus support +IBUS_REQUIRED_VERSION=1.4.99 + +AC_ARG_ENABLE(ibus, + AS_HELP_STRING([--disable-ibus], + [Disable IBus support]), + enable_ibus=$enableval, + enable_ibus=yes) + +if test "x$enable_ibus" = "xyes" ; then + IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" + AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +else + IBUS_MODULE= +fi + +dnl ============================================== +dnl Check that we meet the dependencies +dnl ============================================== + +GLIB_REQUIRED_VERSION=2.31.2 +GTK_REQUIRED_VERSION=3.5.13 +PA_REQUIRED_VERSION=2.0 +CANBERRA_REQUIRED_VERSION=0.13 +GDKPIXBUF_REQUIRED_VERSION=2.23.0 +POLKIT_REQUIRED_VERSION=0.103 +GSD_REQUIRED_VERSION=3.6.0 +NETWORK_MANAGER_REQUIRED_VERSION=0.8.992 +LIBNOTIFY_REQUIRED_VERSION=0.7.3 +GNOME_DESKTOP_REQUIRED_VERSION=3.5.91 +SCHEMAS_REQUIRED_VERSION=3.7.2.2 +LIBWACOM_REQUIRED_VERSION=0.6 +CLUTTER_REQUIRED_VERSION=1.11.3 +GOA_REQUIRED_VERSION=3.5.90 + +COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gthread-2.0 + gio-2.0 + gio-unix-2.0 + gsettings-desktop-schemas >= $SCHEMAS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION" + +PKG_CHECK_MODULES(LIBGNOME_CONTROL_CENTER, $COMMON_MODULES) +PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig) +PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11) +PKG_CHECK_MODULES(SHELL, $COMMON_MODULES libgnome-menu-3.0 gio-unix-2.0 x11) +PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION) +PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0 x11) +PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0 gl x11 + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + x11) +PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11) +PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(ONLINE_ACCOUNTS_PANEL, $COMMON_MODULES goa-1.0 goa-backend-1.0 >= $GOA_REQUIRED_VERSION) +PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 + gnome-settings-daemon >= $GSD_REQUIRED_VERSION) +PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) +PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION) +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) +PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 + libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION + libpulse >= $PA_REQUIRED_VERSION + libpulse-mainloop-glib >= $PA_REQUIRED_VERSION) +PKG_CHECK_MODULES(UNIVERSAL_ACCESS_PANEL, $COMMON_MODULES) +PKG_CHECK_MODULES(USER_ACCOUNTS_PANEL, $COMMON_MODULES + polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION + gnome-desktop-3.0 + gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION + pwquality + $SYSTEMD) + +GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas` +AC_SUBST(GDESKTOP_PREFIX) + +# Check for NetworkManager ~0.9 +PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-util >= $NETWORK_MANAGER_REQUIRED_VERSION + libnm-gtk >= $NETWORK_MANAGER_REQUIRED_VERSION, + [have_networkmanager=yes], have_networkmanager=no) +if test "x$have_networkmanager" = xno ; then + AC_MSG_WARN(*** Network panel will not be built (NetworkManager ~0.9 or newer not found) ***) +fi +AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes]) + +# Check for gnome-bluetooth +PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5, + [have_bluetooth=yes], have_bluetooth=no) +AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes]) + +# Check for CUPS 1.4 or newer +AC_ARG_ENABLE([cups], + AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, + [enable_cups=yes]) + +if test x"$enable_cups" != x"no" ; then + AC_PROG_SED + + AC_PATH_PROG(CUPS_CONFIG, cups-config) + + if test x$CUPS_CONFIG = x; then + AC_MSG_ERROR([cups-config not found but CUPS support requested]) + fi + + CUPS_API_VERSION=`$CUPS_CONFIG --api-version` + CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` + CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` + + AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h cups/ppd.h],, + AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) + + if ! test $CUPS_API_MAJOR -gt 1 -o \ + $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then + AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) + fi + + CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` + CUPS_LIBS=`$CUPS_CONFIG --libs` + AC_SUBST(CUPS_CFLAGS) + AC_SUBST(CUPS_LIBS) +fi + +AM_CONDITIONAL(BUILD_PRINTERS, [test x"$enable_cups" = x"yes"]) + +# Optional dependency for the user accounts panel +AC_ARG_WITH([cheese], + AS_HELP_STRING([--with-cheese], [enable cheese webcam support]),, + with_cheese=auto) + +if test x"$with_cheese" != x"no" ; then + PKG_CHECK_MODULES(CHEESE, gstreamer-1.0 cheese-gtk >= 3.5.91 cheese clutter-gtk-1.0, [have_cheese=yes], [have_cheese=no]) + if test x${have_cheese} = xyes; then + AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support]) + fi + if test x${with_cheese} = xyes && test x${have_cheese} = xno; then + AC_MSG_ERROR([Cheese configured but not found]) + fi +else + have_cheese=no +fi +AM_CONDITIONAL(BUILD_CHEESE, test x${have_cheese} = xyes) + +# wacom is disabled for s390/s390x and non Linux platforms (needs udev) +case $host_os in + linux*) + if test "$host_cpu" = s390 -o "$host_cpu" = s390x; then + have_wacom=no + else + PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES + gnome-settings-daemon >= $GSD_REQUIRED_VERSION + xi >= 1.2 x11 libwacom >= $LIBWACOM_REQUIRED_VERSION + gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION) + have_wacom=yes + fi + ;; + *) + have_wacom=no + ;; +esac +AM_CONDITIONAL(BUILD_WACOM, [test x"$have_wacom" = x"yes"]) + +# This is a hard-dependency for the region and user-accounts panels +PKG_CHECK_MODULES(ISOCODES, iso-codes) + +AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix]) +ISO_CODES=iso-codes + +# Kerberos kerberos support +AC_PATH_PROG(KRB5_CONFIG, krb5-config, no) +if test "$KRB5_CONFIG" = "no"; then + AC_MSG_ERROR([krb5-config executable not found in your path - should be installed with the kerberos libraries]) +fi + +AC_MSG_CHECKING(for krb5 libraries and flags) +KRB5_CFLAGS="`$KRB5_CONFIG --cflags`" +KRB5_LIBS="`$KRB5_CONFIG --libs`" +AC_MSG_RESULT($KRB5_CFLAGS $KRB5_LIBS) + +AC_SUBST(KRB5_CFLAGS) +AC_SUBST(KRB5_LIBS) + +USER_ACCOUNTS_PANEL_CFLAGS="$USER_ACCOUNTS_PANEL_CFLAGS $KRB5_CFLAGS" +USER_ACCOUNTS_PANEL_LIBS="$USER_ACCOUNTS_PANEL_LIBS $KRB5_LIBS" + +dnl ============================================== +dnl End: Check that we meet the dependencies +dnl ============================================== + +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal, no) + +if test x"$GLIB_GENMARSHAL" = xno; then + AC_MSG_ERROR([glib-genmarshal executable not found in your path - should be installed with glib]) +fi + +AC_SUBST(GLIB_GENMARSHAL) + +dnl ======================================= +dnl Panels +dnl ======================================= + +PANELS_DIR="${libdir}/control-center-1/panels" +AC_SUBST(PANELS_DIR) + +PANEL_CFLAGS="-I\$(top_srcdir)/ -DG_LOG_DOMAIN=\"\\\"\$(cappletname)-cc-panel\\\"\"" +AC_SUBST(PANEL_CFLAGS) + +PANEL_LIBS="\$(top_builddir)/shell/libgnome-control-center.la" +AC_SUBST(PANEL_LIBS) + +PANEL_LDFLAGS="-export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload)'" +AC_SUBST(PANEL_LDFLAGS) + +dnl ============================================== +dnl libsocialweb +dnl ============================================== + +AC_MSG_CHECKING([Enable libsocialweb support]) +AC_ARG_WITH([libsocialweb], + AS_HELP_STRING([--with-libsocialweb], + [enable libsocialweb support]),, + [with_libsocialweb=no]) +AC_MSG_RESULT([$with_libsocialweb]) + +if test "x$with_libsocialweb" == "xyes"; then + PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client) + AC_DEFINE(HAVE_LIBSOCIALWEB, 1, [Defined if libsocialweb is available]) +fi +AM_CONDITIONAL(WITH_LIBSOCIALWEB, test "x$with_libsocialweb" = "xyes") + + +dnl ======================================= +dnl Update Mime Database +dnl ======================================= + +AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) + +AC_ARG_ENABLE(update-mimedb, + AS_HELP_STRING([--disable-update-mimedb], + [do not update mime database after installation]),, + enable_update_mimedb=yes) +AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes) + +CONTROL_CENTER_VERSION=gnome_control_center_version +AC_SUBST(CONTROL_CENTER_VERSION) + +dnl ======================================= +dnl Finish +dnl ======================================= + +# Turn on the additional warnings last + +AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes + else + set_more_warnings=no + fi]) + +AC_MSG_CHECKING(for more warnings) +if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then + AC_MSG_RESULT(yes) + CFLAGS="\ + -Wall -Wclobbered -Wempty-body -Wignored-qualifiers \ + -Wmissing-field-initializers -Wmissing-parameter-type \ + -Wold-style-declaration -Woverride-init -Wtype-limits \ + -Wuninitialized \ + -Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wpointer-arith \ + -Wcast-align -Wsign-compare \ + $CFLAGS" + + # Only add this when optimizing is enabled (default) + AC_MSG_CHECKING([whether optimization is enabled]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 + #error No optimization + #endif + ]], [[]])], + [has_optimization=yes], + [has_optimization=no]) + if test $has_optimization = yes; then + CFLAGS="$CFLAGS -Wp,-D_FORTIFY_SOURCE=2" + fi + AC_MSG_RESULT($has_optimization) + + for option in -Wno-strict-aliasing -Wno-sign-compare; do + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $option" + AC_MSG_CHECKING([whether gcc understands $option]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [has_option=yes], + [has_option=no]) + if test $has_option = no; then + CFLAGS="$SAVE_CFLAGS" + fi + AC_MSG_RESULT($has_option) + unset has_option + unset SAVE_CFLAGS + done + unset option +else + AC_MSG_RESULT(no) +fi + + +AC_OUTPUT([ +Makefile +shell/libgnome-control-center.pc +panels/Makefile +panels/common/Makefile +panels/background/Makefile +panels/background/gnome-background-panel.desktop.in +panels/bluetooth/Makefile +panels/bluetooth/gnome-bluetooth-panel.desktop.in +panels/datetime/Makefile +panels/datetime/gnome-datetime-panel.desktop.in +panels/datetime/po-timezones/Makefile +panels/display/Makefile +panels/display/gnome-display-panel.desktop.in +panels/keyboard/Makefile +panels/keyboard/gnome-keyboard-panel.desktop.in +panels/keyboard/gnome-keybindings.pc +panels/region/Makefile +panels/region/gnome-region-panel.desktop.in +panels/mouse/Makefile +panels/mouse/gnome-mouse-panel.desktop.in +panels/online-accounts/Makefile +panels/online-accounts/gnome-online-accounts-panel.desktop.in +panels/online-accounts/icons/Makefile +panels/online-accounts/icons/16x16/Makefile +panels/online-accounts/icons/22x22/Makefile +panels/online-accounts/icons/24x24/Makefile +panels/online-accounts/icons/32x32/Makefile +panels/online-accounts/icons/48x48/Makefile +panels/online-accounts/icons/256x256/Makefile +panels/sound/Makefile +panels/sound/data/Makefile +panels/sound/data/gnome-sound-panel.desktop.in +panels/sound/data/symbolic-icons/Makefile +panels/sound/data/symbolic-icons/scalable/Makefile +panels/sound/data/symbolic-icons/scalable/status/Makefile +panels/sound/data/icons/Makefile +panels/sound/data/icons/16x16/Makefile +panels/sound/data/icons/16x16/apps/Makefile +panels/sound/data/icons/16x16/devices/Makefile +panels/sound/data/icons/16x16/status/Makefile +panels/sound/data/icons/22x22/Makefile +panels/sound/data/icons/22x22/apps/Makefile +panels/sound/data/icons/22x22/status/Makefile +panels/sound/data/icons/24x24/Makefile +panels/sound/data/icons/24x24/apps/Makefile +panels/sound/data/icons/24x24/devices/Makefile +panels/sound/data/icons/24x24/status/Makefile +panels/sound/data/icons/32x32/Makefile +panels/sound/data/icons/32x32/apps/Makefile +panels/sound/data/icons/32x32/devices/Makefile +panels/sound/data/icons/32x32/status/Makefile +panels/sound/data/icons/48x48/Makefile +panels/sound/data/icons/48x48/apps/Makefile +panels/sound/data/icons/48x48/devices/Makefile +panels/sound/data/icons/scalable/Makefile +panels/sound/data/icons/scalable/apps/Makefile +panels/sound/data/icons/scalable/devices/Makefile +panels/sound/data/sounds/Makefile +panels/screen/Makefile +panels/screen/gnome-screen-panel.desktop.in +panels/info/Makefile +panels/info/gnome-info-panel.desktop.in +panels/power/Makefile +panels/power/gnome-power-panel.desktop.in +panels/power/icons/Makefile +panels/power/icons/16x16/Makefile +panels/power/icons/22x22/Makefile +panels/power/icons/24x24/Makefile +panels/power/icons/32x32/Makefile +panels/power/icons/48x48/Makefile +panels/power/icons/256x256/Makefile +panels/color/Makefile +panels/color/gnome-color-panel.desktop.in +panels/color/icons/Makefile +panels/color/icons/16x16/Makefile +panels/color/icons/22x22/Makefile +panels/color/icons/24x24/Makefile +panels/color/icons/32x32/Makefile +panels/color/icons/48x48/Makefile +panels/color/icons/64x64/Makefile +panels/color/icons/256x256/Makefile +panels/color/icons/scalable/Makefile +panels/printers/Makefile +panels/printers/gnome-printers-panel.desktop.in +panels/network/Makefile +panels/network/gnome-network-panel.desktop.in +panels/universal-access/Makefile +panels/universal-access/gnome-universal-access-panel.desktop.in +panels/user-accounts/Makefile +panels/user-accounts/data/Makefile +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in +panels/user-accounts/data/faces/Makefile +panels/user-accounts/data/icons/Makefile +panels/wacom/Makefile +panels/wacom/calibrator/Makefile +panels/wacom/gnome-wacom-panel.desktop.in +po/Makefile.in +shell/Makefile +shell/gnome-control-center.desktop.in +man/Makefile +]) + +AC_MSG_NOTICE([gnome-control-center was configured with the following options:]) +if test "x$have_networkmanager" = "xyes"; then + AC_MSG_NOTICE([** NetworkManager (Network panel)]) +else + AC_MSG_NOTICE([ Network panel disabled]) +fi +if test "x$have_bluetooth" = "xyes"; then + AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)]) +else + AC_MSG_NOTICE([ Bluetooth panel disabled]) +fi +if test "x$enable_cups" = "xyes"; then + AC_MSG_NOTICE([** CUPS (Printers panel)]) +else + AC_MSG_NOTICE([ Printers panel disabled]) +fi +if test "x$have_cheese" = "xyes"; then + AC_MSG_NOTICE([** Cheese (Users panel webcam support)]) +else + AC_MSG_NOTICE([ Users panel webcam support disabled]) +fi +if test "x$with_libsocialweb" = "xyes"; then + AC_MSG_NOTICE([** libsocialweb (Background panel Flickr support)]) +else + AC_MSG_NOTICE([ Background panel Flickr support disabled]) +fi +if test "x$with_systemd" = "xyes"; then + AC_MSG_NOTICE([** systemd (Systemd session tracking)]) +else + AC_MSG_NOTICE([ Using ConsoleKit for session tracking]) +fi +if test "x$have_wacom" = "xyes"; then + AC_MSG_NOTICE([** wacom (Wacom tablet panel)]) +else + AC_MSG_NOTICE([ Wacom panel disabled]) +fi +if test "x$enable_ibus" == "xyes"; then + AC_MSG_NOTICE([** IBus (Region panel IBus support)]) +else + AC_MSG_NOTICE([ Region panel IBus support disabled]) +fi +AC_MSG_NOTICE([End options]) diff -Nru gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/panels/info/Makefile.am gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/panels/info/Makefile.am --- gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/panels/info/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/ubuntu-gnome-version.patch/panels/info/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,56 @@ +cappletname = info + +INCLUDES = \ + $(PANEL_CFLAGS) \ + $(INFO_PANEL_CFLAGS) \ + -DGNOMECC_UI_DIR="\"$(uidir)\"" \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + -DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \ + -DDATADIR="\"$(datadir)\"" \ + -DLIBEXECDIR="\"$(libexecdir)\"" \ + $(NULL) + +noinst_PROGRAMS = test-hostname +test_hostname_SOURCES = hostname-helper.c hostname-helper.h test-hostname.c +test_hostname_LDADD = $(PANEL_LIBS) $(INFO_PANEL_LIBS) +test_hostname_CFLAGS = $(INCLUDES) + +all-local: check-local + +check-local: test-hostname + $(builddir)/test-hostname $(srcdir)/hostnames-test.txt > /dev/null + +ccpanelsdir = $(PANELS_DIR) +ccpanels_LTLIBRARIES = libinfo.la + +libinfo_la_SOURCES = \ + info-module.c \ + cc-info-panel.c \ + cc-info-panel.h \ + hostname-helper.c \ + hostname-helper.h \ + gsd-disk-space-helper.h \ + gsd-disk-space-helper.c + +libinfo_la_LIBADD = $(PANEL_LIBS) $(INFO_PANEL_LIBS) +libinfo_la_LDFLAGS = $(PANEL_LDFLAGS) + +uidir = $(pkgdatadir)/ui +dist_ui_DATA = info.ui GnomeLogoVerticalMedium.svg + +@INTLTOOL_DESKTOP_RULE@ + +desktopdir = $(datadir)/applications +desktop_in_files = gnome-info-panel.desktop.in +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) + +SPACEDIR=$(top_srcdir)/../gnome-settings-daemon/plugins/housekeeping/ +SPACEFILES=gsd-disk-space-helper.c gsd-disk-space-helper.h +update-from-gsd: + FILES="$(SPACEFILES)" DIR="$(SPACEDIR)" $(top_srcdir)/update-from-gsd.sh && changed=true ; \ + git commit -m "info: Update from gnome-settings-daemon" $(SPACEFILES) + +CLEANFILES = $(desktop_in_files) $(desktop_DATA) +EXTRA_DIST = hostnames-test.txt + +-include $(top_srcdir)/git.mk diff -Nru gnome-control-center-3.6.3/.pc/ubuntu_update_lock_and_power_settings.patch/panels/screen/cc-screen-panel.c gnome-control-center-3.6.3/.pc/ubuntu_update_lock_and_power_settings.patch/panels/screen/cc-screen-panel.c --- gnome-control-center-3.6.3/.pc/ubuntu_update_lock_and_power_settings.patch/panels/screen/cc-screen-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/ubuntu_update_lock_and_power_settings.patch/panels/screen/cc-screen-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,573 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "cc-screen-panel.h" + +CC_PANEL_REGISTER (CcScreenPanel, cc_screen_panel) + +#define SCREEN_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SCREEN_PANEL, CcScreenPanelPrivate)) + +#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s)) + +struct _CcScreenPanelPrivate +{ + GSettings *lock_settings; + GSettings *gsd_settings; + GSettings *session_settings; + GSettings *lockdown_settings; + GCancellable *cancellable; + GtkBuilder *builder; + GDBusProxy *proxy; + gboolean setting_brightness; +}; + + +static void +cc_screen_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_screen_panel_dispose (GObject *object) +{ + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (object)->priv; + + if (priv->lock_settings) + { + g_object_unref (priv->lock_settings); + priv->lock_settings = NULL; + } + if (priv->gsd_settings) + { + g_object_unref (priv->gsd_settings); + priv->gsd_settings = NULL; + } + if (priv->session_settings) + { + g_object_unref (priv->session_settings); + priv->session_settings = NULL; + } + if (priv->lockdown_settings) + { + g_object_unref (priv->lockdown_settings); + priv->lockdown_settings = NULL; + } + if (priv->cancellable != NULL) + { + g_cancellable_cancel (priv->cancellable); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + if (priv->builder != NULL) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + if (priv->proxy != NULL) + { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + G_OBJECT_CLASS (cc_screen_panel_parent_class)->dispose (object); +} + +static void +on_lock_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "lock-delay") == FALSE) + return; +} + +static void +update_lock_screen_sensitivity (CcScreenPanel *self) +{ + GtkWidget *widget; + gboolean locked; + + widget = WID ("screen_lock_main_box"); + locked = g_settings_get_boolean (self->priv->lockdown_settings, "disable-lock-screen"); + gtk_widget_set_sensitive (widget, !locked); +} + +static void +on_lockdown_settings_changed (GSettings *settings, + const char *key, + CcScreenPanel *panel) +{ + if (g_str_equal (key, "disable-lock-screen") == FALSE) + return; + + update_lock_screen_sensitivity (panel); +} + +static const char * +cc_screen_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/prefs-display"; + else + return "help:gnome-help/prefs-display"; +} + +static void +cc_screen_panel_class_init (CcScreenPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcScreenPanelPrivate)); + + object_class->get_property = cc_screen_panel_get_property; + object_class->set_property = cc_screen_panel_set_property; + object_class->dispose = cc_screen_panel_dispose; + + panel_class->get_help_uri = cc_screen_panel_get_help_uri; +} + +static void +set_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* not setting, so pay attention to changed signals */ + priv->setting_brightness = FALSE; + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + g_printerr ("Error setting brightness: %s\n", error->message); + g_error_free (error); + return; + } +} + +static void +brightness_slider_value_changed_cb (GtkRange *range, gpointer user_data) +{ + guint percentage; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + /* do not loop */ + if (priv->setting_brightness) + return; + + priv->setting_brightness = TRUE; + + /* push this to g-p-m */ + percentage = (guint) gtk_range_get_value (range); + g_dbus_proxy_call (priv->proxy, + "SetPercentage", + g_variant_new ("(u)", + percentage), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + set_brightness_cb, + user_data); +} + +static void +get_brightness_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GVariant *result; + guint brightness; + GtkRange *range; + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (result == NULL) + { + /* We got cancelled, so we're probably exiting */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + gtk_widget_hide (WID ("screen_brightness_hscale")); + gtk_widget_hide (WID ("screen_auto_reduce_checkbutton")); + gtk_widget_hide (WID ("brightness-frame")); + g_object_set (G_OBJECT (WID ("turn-off-alignment")), "left-padding", 0, NULL); + + if (error->message && + strstr (error->message, "No backlight devices present") == NULL) + { + g_warning ("Error getting brightness: %s", error->message); + } + g_error_free (error); + return; + } + + /* set the slider */ + g_variant_get (result, + "(u)", + &brightness); + range = GTK_RANGE (WID ("screen_brightness_hscale")); + gtk_range_set_range (range, 0, 100); + gtk_range_set_increments (range, 1, 10); + gtk_range_set_value (range, brightness); + g_signal_connect (range, + "value-changed", + G_CALLBACK (brightness_slider_value_changed_cb), + user_data); + g_variant_unref (result); +} + +static void +on_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CcScreenPanel *self = CC_SCREEN_PANEL (user_data); + + if (g_strcmp0 (signal_name, "Changed") == 0) + { + /* changed, but ignoring */ + if (self->priv->setting_brightness) + return; + + /* retrieve the value again from g-s-d */ + g_dbus_proxy_call (self->priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + self->priv->cancellable, + get_brightness_cb, + user_data); + } +} + +static void +got_power_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + CcScreenPanelPrivate *priv = CC_SCREEN_PANEL (user_data)->priv; + + priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (priv->proxy == NULL) + { + g_printerr ("Error creating proxy: %s\n", error->message); + g_error_free (error); + return; + } + + /* we want to change the bar if the user presses brightness buttons */ + g_signal_connect (priv->proxy, + "g-signal", + G_CALLBACK (on_signal), + user_data); + + /* get the initial state */ + g_dbus_proxy_call (priv->proxy, + "GetPercentage", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 200, /* we don't want to randomly move the bar */ + priv->cancellable, + get_brightness_cb, + user_data); +} + +static void +set_idle_delay_from_dpms (CcScreenPanel *self, + int value) +{ + guint off_delay; + + off_delay = 0; + + if (value > 0) + off_delay = (guint) value; + + g_settings_set (self->priv->session_settings, "idle-delay", "u", off_delay); +} + +static void +dpms_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &value, + -1); + + /* set both battery and ac keys */ + g_settings_set_int (self->priv->gsd_settings, "sleep-display-ac", value); + g_settings_set_int (self->priv->gsd_settings, "sleep-display-battery", value); + + set_idle_delay_from_dpms (self, value); +} + +static void +lock_combo_changed_cb (GtkWidget *widget, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint delay; + gboolean ret; + + /* no selection */ + ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter); + if (!ret) + return; + + /* get entry */ + model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget)); + gtk_tree_model_get (model, &iter, + 1, &delay, + -1); + g_settings_set (self->priv->lock_settings, "lock-delay", "u", delay); +} + +static void +set_dpms_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the AC setting */ + value = g_settings_get_int (self->priv->gsd_settings, "sleep-display-ac"); + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +set_lock_value_for_combo (GtkComboBox *combo_box, CcScreenPanel *self) +{ + GtkTreeIter iter; + GtkTreeModel *model; + guint value; + gint value_tmp, value_prev; + gboolean ret; + guint i; + + /* get entry */ + model = gtk_combo_box_get_model (combo_box); + ret = gtk_tree_model_get_iter_first (model, &iter); + if (!ret) + return; + + value_prev = 0; + i = 0; + + /* try to make the UI match the lock setting */ + g_settings_get (self->priv->lock_settings, "lock-delay", "u", &value); + + do + { + gtk_tree_model_get (model, &iter, + 1, &value_tmp, + -1); + if (value == value_tmp || + (value_tmp > value_prev && value < value_tmp)) + { + gtk_combo_box_set_active_iter (combo_box, &iter); + return; + } + value_prev = value_tmp; + i++; + } while (gtk_tree_model_iter_next (model, &iter)); + + /* If we didn't find the setting in the list */ + gtk_combo_box_set_active (combo_box, i - 1); +} + +static void +cc_screen_panel_init (CcScreenPanel *self) +{ + GError *error; + GtkWidget *widget; + + self->priv = SCREEN_PANEL_PRIVATE (self); + + self->priv->builder = gtk_builder_new (); + + error = NULL; + gtk_builder_add_from_file (self->priv->builder, + GNOMECC_UI_DIR "/screen.ui", + &error); + + if (error != NULL) + { + g_warning ("Could not load interface file: %s", error->message); + g_error_free (error); + return; + } + + self->priv->cancellable = g_cancellable_new (); + + /* get initial brightness version */ + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + self->priv->cancellable, + got_power_proxy_cb, + self); + + self->priv->lock_settings = g_settings_new ("org.gnome.desktop.screensaver"); + g_signal_connect (self->priv->lock_settings, + "changed", + G_CALLBACK (on_lock_settings_changed), + self); + self->priv->gsd_settings = g_settings_new ("org.gnome.settings-daemon.plugins.power"); + self->priv->session_settings = g_settings_new ("org.gnome.desktop.session"); + self->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect (self->priv->lockdown_settings, + "changed", + G_CALLBACK (on_lockdown_settings_changed), + self); + + /* bind the auto dim checkbox */ + widget = WID ("screen_auto_reduce_checkbutton"); + g_settings_bind (self->priv->gsd_settings, + "idle-dim-battery", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* display off time */ + widget = WID ("screen_brightness_combobox"); + set_dpms_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (dpms_combo_changed_cb), + self); + + /* bind the screen lock checkbox */ + widget = WID ("screen_lock_on_switch"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + /* lock time */ + widget = WID ("screen_lock_combobox"); + set_lock_value_for_combo (GTK_COMBO_BOX (widget), self); + g_signal_connect (widget, "changed", + G_CALLBACK (lock_combo_changed_cb), + self); + + widget = WID ("screen_lock_hbox"); + g_settings_bind (self->priv->lock_settings, + "lock-enabled", + widget, "sensitive", + G_SETTINGS_BIND_GET); + + widget = WID ("show_notifications_check"); + g_settings_bind (self->priv->lock_settings, + "show-notifications", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_hide (widget); + + update_lock_screen_sensitivity (self); + + /* bind the screen lock suspend checkbutton */ + widget = WID ("screen_lock_suspend_checkbutton"); + g_settings_bind (self->priv->lock_settings, + "ubuntu-lock-on-suspend", + widget, "active", + G_SETTINGS_BIND_DEFAULT); + + widget = WID ("screen_vbox"); + gtk_widget_reparent (widget, (GtkWidget *) self); + g_object_set (self, "valign", GTK_ALIGN_START, NULL); +} + +void +cc_screen_panel_register (GIOModule *module) +{ + cc_screen_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_SCREEN_PANEL, + "screen", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/ubuntu_update_translations_template.patch/po/POTFILES.in gnome-control-center-3.6.3/.pc/ubuntu_update_translations_template.patch/po/POTFILES.in --- gnome-control-center-3.6.3/.pc/ubuntu_update_translations_template.patch/po/POTFILES.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/ubuntu_update_translations_template.patch/po/POTFILES.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,137 @@ +# Add files with translateable strings here. +# Please keep this file sorted alphabetically. +[encoding: UTF-8] +[type: gettext/glade]panels/background/background.ui +panels/background/bg-colors-source.c +panels/background/cc-background-chooser-dialog.c +panels/background/cc-background-item.c +panels/background/cc-background-panel.c +panels/background/gnome-background-panel.desktop.in.in +panels/bluetooth/gnome-bluetooth-panel.desktop.in.in +[type: gettext/glade]panels/bluetooth/bluetooth.ui +panels/bluetooth/cc-bluetooth-panel.c +panels/color/cc-color-panel.c +[type: gettext/glade]panels/color/color.ui +panels/color/gnome-color-panel.desktop.in.in +panels/common/cc-common-language.c +panels/common/cc-language-chooser.c +panels/common/gdm-languages.c +[type: gettext/glade]panels/common/language-chooser.ui +[type: gettext/glade]panels/datetime/datetime.ui +panels/datetime/gnome-datetime-panel.desktop.in.in +panels/datetime/org.gnome.controlcenter.datetime.policy.in +panels/display/cc-display-panel.c +[type: gettext/glade]panels/display/display-capplet.ui +panels/display/gnome-display-panel.desktop.in.in +panels/info/cc-info-panel.c +panels/info/gnome-info-panel.desktop.in.in +[type: gettext/glade]panels/info/info.ui +panels/keyboard/00-multimedia.xml.in +panels/keyboard/01-input-sources.xml.in +panels/keyboard/01-launchers.xml.in +panels/keyboard/01-screenshot.xml.in +panels/keyboard/01-system.xml.in +panels/keyboard/50-accessibility.xml.in +panels/keyboard/cc-keyboard-option.c +panels/keyboard/gnome-keyboard-panel.desktop.in.in +[type: gettext/glade]panels/keyboard/gnome-keyboard-panel.ui +panels/keyboard/keyboard-shortcuts.c +panels/mouse/cc-mouse-panel.c +panels/mouse/gnome-mouse-panel.desktop.in.in +panels/mouse/gnome-mouse-properties.c +[type: gettext/glade]panels/mouse/gnome-mouse-properties.ui +panels/mouse/gnome-mouse-test.c +[type: gettext/glade]panels/mouse/gnome-mouse-test.ui +panels/network/cc-network-panel.c +panels/network/gnome-network-panel.desktop.in.in +panels/network/net-device-mobile.c +panels/network/net-device-wifi.c +panels/network/net-device-wired.c +panels/network/net-proxy.c +panels/network/net-vpn.c +[type: gettext/glade]panels/network/network-mobile.ui +[type: gettext/glade]panels/network/network-proxy.ui +[type: gettext/glade]panels/network/network.ui +[type: gettext/glade]panels/network/network-vpn.ui +[type: gettext/glade]panels/network/network-wifi.ui +[type: gettext/glade]panels/network/network-wired.ui +panels/network/panel-common.c +panels/online-accounts/cc-online-accounts-add-account-dialog.c +panels/online-accounts/cc-online-accounts-panel.c +panels/online-accounts/gnome-online-accounts-panel.desktop.in.in +[type: gettext/glade]panels/online-accounts/online-accounts.ui +panels/power/cc-power-panel.c +panels/power/gnome-power-panel.desktop.in.in +[type: gettext/glade]panels/power/power.ui +panels/printers/cc-printers-panel.c +panels/printers/gnome-printers-panel.desktop.in.in +[type: gettext/glade]panels/printers/jobs-dialog.ui +[type: gettext/glade]panels/printers/new-printer-dialog.ui +[type: gettext/glade]panels/printers/options-dialog.ui +[type: gettext/glade]panels/printers/ppd-selection-dialog.ui +panels/printers/pp-ipp-option-widget.c +panels/printers/pp-jobs-dialog.c +panels/printers/pp-new-printer-dialog.c +panels/printers/pp-options-dialog.c +panels/printers/pp-ppd-option-widget.c +panels/printers/pp-ppd-selection-dialog.c +[type: gettext/glade]panels/printers/printers.ui +panels/region/gnome-region-panel.desktop.in.in +panels/region/gnome-region-panel-formats.c +[type: gettext/glade]panels/region/gnome-region-panel-input-chooser.ui +panels/region/gnome-region-panel-system.c +[type: gettext/glade]panels/region/gnome-region-panel.ui +panels/screen/gnome-screen-panel.desktop.in.in +[type: gettext/glade]panels/screen/screen.ui +panels/sound/applet-main.c +panels/sound/cc-sound-panel.c +panels/sound/data/gnome-sound-applet.desktop.in +panels/sound/data/gnome-sound-panel.desktop.in.in +panels/sound/data/sounds/gnome-sounds-default.xml.in.in +panels/sound/gvc-applet.c +panels/sound/gvc-balance-bar.c +panels/sound/gvc-channel-bar.c +panels/sound/gvc-combo-box.c +panels/sound/gvc-mixer-control.c +panels/sound/gvc-mixer-dialog.c +panels/sound/gvc-sound-theme-chooser.c +panels/sound/gvc-speaker-test.c +panels/sound/gvc-stream-status-icon.c +panels/sound/sound-theme-file-utils.c +panels/universal-access/cc-ua-panel.c +panels/universal-access/gnome-universal-access-panel.desktop.in.in +[type: gettext/glade]panels/universal-access/uap.ui +panels/universal-access/zoom-options.c +[type: gettext/glade]panels/universal-access/zoom-options.ui +[type: gettext/glade]panels/user-accounts/data/account-dialog.ui +[type: gettext/glade]panels/user-accounts/data/account-fingerprint.ui +panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in +[type: gettext/glade]panels/user-accounts/data/password-dialog.ui +[type: gettext/glade]panels/user-accounts/data/photo-dialog.ui +[type: gettext/glade]panels/user-accounts/data/user-accounts-dialog.ui +panels/user-accounts/org.gnome.controlcenter.user-accounts.policy.in +panels/user-accounts/pw-utils.c +panels/user-accounts/run-passwd.c +panels/user-accounts/um-account-dialog.c +panels/user-accounts/um-account-type.c +panels/user-accounts/um-fingerprint-dialog.c +panels/user-accounts/um-password-dialog.c +panels/user-accounts/um-photo-dialog.c +panels/user-accounts/um-realm-manager.c +panels/user-accounts/um-user-manager.c +panels/user-accounts/um-user-panel.c +panels/user-accounts/um-utils.c +[type: gettext/glade]panels/wacom/button-mapping.ui +panels/wacom/calibrator/gui_gtk.c +panels/wacom/cc-wacom-mapping-panel.c +panels/wacom/cc-wacom-nav-button.c +panels/wacom/cc-wacom-page.c +panels/wacom/cc-wacom-stylus-page.c +panels/wacom/gnome-wacom-panel.desktop.in.in +[type: gettext/glade]panels/wacom/gnome-wacom-properties.ui +panels/wacom/gsd-wacom-device.c +[type: gettext/glade]panels/wacom/wacom-stylus-page.ui +shell/control-center.c +shell/gnomecc.directory.in +shell/gnome-control-center.desktop.in.in +[type: gettext/glade]shell/shell.ui diff -Nru gnome-control-center-3.6.3/.pc/unity_background_is_appareance.patch/shell/gnome-control-center.c gnome-control-center-3.6.3/.pc/unity_background_is_appareance.patch/shell/gnome-control-center.c --- gnome-control-center-3.6.3/.pc/unity_background_is_appareance.patch/shell/gnome-control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/unity_background_is_appareance.patch/shell/gnome-control-center.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1465 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + + +#include "gnome-control-center.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ +#define GMENU_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "cc-panel.h" +#include "cc-shell.h" +#include "cc-shell-category-view.h" +#include "cc-shell-model.h" +#include "cc-shell-nav-bar.h" + +G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) + +#define CONTROL_CENTER_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_CONTROL_CENTER, GnomeControlCenterPrivate)) + +#define W(b,x) GTK_WIDGET (gtk_builder_get_object (b, x)) + +/* Use a fixed width for the shell, since resizing horizontally is more awkward + * for the user than resizing vertically + * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ +#define FIXED_WIDTH 740 +#define UNITY_FIXED_WIDTH 850 +#define FIXED_HEIGHT 650 +#define SMALL_SCREEN_FIXED_HEIGHT 400 + +#define MIN_ICON_VIEW_HEIGHT 300 + +typedef enum { + SMALL_SCREEN_UNSET, + SMALL_SCREEN_TRUE, + SMALL_SCREEN_FALSE +} CcSmallScreen; + +struct _GnomeControlCenterPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GtkWidget *main_vbox; + GtkWidget *scrolled_window; + GtkWidget *search_scrolled; + GtkWidget *current_panel_box; + GtkWidget *current_panel; + char *current_panel_id; + GtkWidget *window; + GtkWidget *search_entry; + GtkWidget *lock_button; + GPtrArray *custom_widgets; + GtkWidget *nav_bar; + + GMenuTree *menu_tree; + GtkListStore *store; + GHashTable *category_views; + + GtkTreeModel *search_filter; + GtkWidget *search_view; + gchar *filter_string; + + guint32 last_time; + + GIOExtensionPoint *extension_point; + + gchar *default_window_title; + gchar *default_window_icon; + + int monitor_num; + CcSmallScreen small_screen; +}; + +/* Notebook helpers */ +static GtkWidget * +notebook_get_selected_page (GtkWidget *notebook) +{ + int curr; + + curr = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + if (curr == -1) + return NULL; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), curr); +} + +static void +notebook_select_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't select GtkNotebook page %p", page); +} + +static void +notebook_remove_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't find GtkNotebook page to remove %p", page); +} + +static void +notebook_add_page (GtkWidget *notebook, + GtkWidget *page) +{ + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); +} + +static const gchar * +get_icon_name_from_g_icon (GIcon *gicon) +{ + const gchar * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return names[i]; + } + + return NULL; +} + +static gboolean +activate_panel (GnomeControlCenter *shell, + const gchar *id, + const gchar **argv, + const gchar *desktop_file, + const gchar *name, + GIcon *gicon) +{ + GnomeControlCenterPrivate *priv = shell->priv; + GType panel_type = G_TYPE_INVALID; + GList *panels, *l; + GtkWidget *box; + const gchar *icon_name; + + /* check if there is an plugin that implements this panel */ + panels = g_io_extension_point_get_extensions (priv->extension_point); + + if (!desktop_file) + return FALSE; + if (!id) + return FALSE; + + for (l = panels; l != NULL; l = l->next) + { + GIOExtension *extension; + const gchar *name; + + extension = l->data; + + name = g_io_extension_get_name (extension); + + if (!g_strcmp0 (name, id)) + { + panel_type = g_io_extension_get_type (extension); + break; + } + } + + if (panel_type == G_TYPE_INVALID) + { + GKeyFile *key_file; + + /* It might be an external panel */ + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, desktop_file, G_KEY_FILE_NONE, NULL)) + { + gchar *command; + + command = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + if (command && command[0]) + { + g_spawn_command_line_async (command, NULL); + g_free (command); + } + } + + g_key_file_free (key_file); + return FALSE; + } + + /* create the panel plugin */ + priv->current_panel = g_object_new (panel_type, "shell", shell, "argv", argv, NULL); + cc_shell_set_active_panel (CC_SHELL (shell), CC_PANEL (priv->current_panel)); + gtk_widget_show (priv->current_panel); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), + cc_panel_get_permission (CC_PANEL (priv->current_panel))); + + box = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (box), 6, 6, 6, 6); + + gtk_container_add (GTK_CONTAINER (box), priv->current_panel); + + gtk_widget_set_name (box, id); + notebook_add_page (priv->notebook, box); + + /* switch to the new panel */ + gtk_widget_show (box); + notebook_select_page (priv->notebook, box); + cc_shell_nav_bar_show_detail_button (CC_SHELL_NAV_BAR(shell->priv->nav_bar), name); + + /* set the title of the window */ + icon_name = get_icon_name_from_g_icon (gicon); + gtk_window_set_role (GTK_WINDOW (priv->window), id); + gtk_window_set_title (GTK_WINDOW (priv->window), name); + gtk_window_set_default_icon_name (icon_name); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), icon_name); + + priv->current_panel_box = box; + + return TRUE; +} + +static void +_shell_remove_all_custom_widgets (GnomeControlCenterPrivate *priv) +{ + GtkBox *box; + GtkWidget *widget; + guint i; + + /* remove from the header */ + box = GTK_BOX (W (priv->builder, "topright")); + for (i = 0; i < priv->custom_widgets->len; i++) + { + widget = g_ptr_array_index (priv->custom_widgets, i); + gtk_container_remove (GTK_CONTAINER (box), widget); + } + g_ptr_array_set_size (priv->custom_widgets, 0); +} + +static void +shell_show_overview_page (GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + + notebook_select_page (priv->notebook, priv->scrolled_window); + + if (priv->current_panel_box) + notebook_remove_page (priv->notebook, priv->current_panel_box); + priv->current_panel = NULL; + priv->current_panel_box = NULL; + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear the search text */ + g_free (priv->filter_string); + priv->filter_string = g_strdup (""); + gtk_entry_set_text (GTK_ENTRY (priv->search_entry), ""); + gtk_widget_grab_focus (priv->search_entry); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), NULL); + + /* reset window title and icon */ + gtk_window_set_role (GTK_WINDOW (priv->window), NULL); + gtk_window_set_title (GTK_WINDOW (priv->window), priv->default_window_title); + gtk_window_set_default_icon_name (priv->default_window_icon); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), + priv->default_window_icon); + + cc_shell_set_active_panel (CC_SHELL (center), NULL); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + cc_shell_nav_bar_hide_detail_button (CC_SHELL_NAV_BAR (priv->nav_bar)); +} + +void +gnome_control_center_set_overview_page (GnomeControlCenter *center) +{ + shell_show_overview_page (center); +} + +static void +item_activated_cb (CcShellCategoryView *view, + gchar *name, + gchar *id, + gchar *desktop_file, + GnomeControlCenter *shell) +{ + GError *err = NULL; + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, &err)) + { + /* TODO: show message to user */ + if (err) + { + g_warning ("Could not active panel \"%s\": %s", id, err->message); + g_error_free (err); + } + } +} + +static gboolean +category_focus_out (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + gtk_icon_view_unselect_all (GTK_ICON_VIEW (view)); + + return FALSE; +} + +static gboolean +category_focus_in (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + GtkTreePath *path; + + if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL)) + { + path = gtk_tree_path_new_from_indices (0, -1); + gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE); + } + + gtk_icon_view_select_path (GTK_ICON_VIEW (view), path); + gtk_tree_path_free (path); + + return FALSE; +} + +static GList * +get_item_views (GnomeControlCenter *shell) +{ + GList *list, *l; + GList *res; + + list = gtk_container_get_children (GTK_CONTAINER (shell->priv->main_vbox)); + res = NULL; + for (l = list; l; l = l->next) + { + if (!CC_IS_SHELL_CATEGORY_VIEW (l->data)) + continue; + res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data))); + } + + g_list_free (list); + + return res; +} + +static gboolean +keynav_failed (GtkIconView *current_view, + GtkDirectionType direction, + GnomeControlCenter *shell) +{ + GList *views, *v; + GtkIconView *new_view; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + gint col, c, dist, d; + GtkTreePath *sel; + gboolean res; + + res = FALSE; + + views = get_item_views (shell); + + for (v = views; v; v = v->next) + { + if (v->data == current_view) + break; + } + + if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL) + { + new_view = v->next->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d < dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL) + { + new_view = v->prev->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d <= dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + g_list_free (views); + + return res; +} + +static gboolean +model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GnomeControlCenterPrivate *priv) +{ + gchar *name, *description; + gchar *needle, *haystack; + gboolean result; + gchar **keywords; + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + COL_DESCRIPTION, &description, + COL_KEYWORDS, &keywords, + -1); + + if (!priv->filter_string || !name) + { + g_free (name); + g_free (description); + g_strfreev (keywords); + return FALSE; + } + + needle = g_utf8_casefold (priv->filter_string, -1); + haystack = g_utf8_casefold (name, -1); + + result = (strstr (haystack, needle) != NULL); + + if (!result && description) + { + gchar *folded; + + folded = g_utf8_casefold (description, -1); + result = (strstr (folded, needle) != NULL); + g_free (folded); + } + + if (!result && keywords) + { + gint i; + gchar *keyword; + + for (i = 0; !result && keywords[i]; i++) + { + keyword = g_utf8_casefold (keywords[i], -1); + result = strstr (keyword, needle) == keyword; + g_free (keyword); + } + } + + g_free (name); + g_free (haystack); + g_free (needle); + g_strfreev (keywords); + + return result; +} + +static gboolean +category_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gchar *filter) +{ + gchar *category; + gboolean result; + + gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1); + + result = (g_strcmp0 (category, filter) == 0); + + g_free (category); + + return result; +} + +static void +search_entry_changed_cb (GtkEntry *entry, + GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + char *str; + + /* if the entry text was set manually (not by the user) */ + if (!g_strcmp0 (priv->filter_string, gtk_entry_get_text (entry))) + return; + + /* Don't re-filter for added trailing or leading spaces */ + str = g_strdup (gtk_entry_get_text (entry)); + g_strstrip (str); + if (!g_strcmp0 (str, priv->filter_string)) + { + g_free (str); + return; + } + + g_free (priv->filter_string); + priv->filter_string = str; + + if (!g_strcmp0 (priv->filter_string, "")) + { + shell_show_overview_page (center); + } + else + { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->search_filter)); + notebook_select_page (priv->notebook, priv->search_scrolled); + } +} + +static gboolean +search_entry_key_press_event_cb (GtkEntry *entry, + GdkEventKey *event, + GnomeControlCenterPrivate *priv) +{ + if (event->keyval == GDK_KEY_Return) + { + GtkTreePath *path; + + path = gtk_tree_path_new_first (); + + priv->last_time = event->time; + + gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->search_view), path); + + gtk_tree_path_free (path); + return TRUE; + } + + if (event->keyval == GDK_KEY_Escape) + { + gtk_entry_set_text (entry, ""); + return TRUE; + } + + return FALSE; +} + +static void +on_search_selection_changed (GtkTreeSelection *selection, + GnomeControlCenter *shell) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + COL_ID, &id, + -1); + + if (id) + cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); + + gtk_tree_selection_unselect_all (selection); + + g_free (id); +} + +static void +setup_search (GnomeControlCenter *shell) +{ + GtkWidget *search_view, *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GnomeControlCenterPrivate *priv = shell->priv; + + g_return_if_fail (priv->store != NULL); + + /* create the search filter */ + priv->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), + NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->search_filter), + (GtkTreeModelFilterVisibleFunc) + model_filter_func, + priv, NULL); + + /* set up the search view */ + priv->search_view = search_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), + GTK_TREE_MODEL (priv->search_filter)); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + "xpad", 15, + "ypad", 10, + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, + "gicon", COL_GICON, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 0, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", COL_NAME, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 15, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Description", renderer, + "text", COL_DESCRIPTION, + NULL); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + priv->search_scrolled = W (priv->builder, "search-scrolled-window"); + gtk_container_add (GTK_CONTAINER (priv->search_scrolled), search_view); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->search_view)), + "changed", + G_CALLBACK (on_search_selection_changed), + shell); + + /* setup the search entry widget */ + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "search-entry"); + priv->search_entry = widget; + priv->filter_string = g_strdup (""); + + g_signal_connect (widget, "changed", G_CALLBACK (search_entry_changed_cb), + shell); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (search_entry_key_press_event_cb), priv); + + gtk_widget_show (priv->search_view); +} + +static void +setup_lock (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + priv->lock_button = W (priv->builder, "lock-button"); +} + +static void +maybe_add_category_view (GnomeControlCenter *shell, + const char *name) +{ + GtkTreeModel *filter; + GtkWidget *categoryview; + + if (g_hash_table_lookup (shell->priv->category_views, name) != NULL) + return; + + if (g_hash_table_size (shell->priv->category_views) > 0) + { + GtkWidget *separator; + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_set_margin_top (separator, 11); + gtk_widget_set_margin_bottom (separator, 10); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), separator, FALSE, FALSE, 0); + gtk_widget_show (separator); + } + + /* create new category view for this category */ + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->priv->store), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + (GtkTreeModelFilterVisibleFunc) category_filter_func, + g_strdup (name), g_free); + + categoryview = cc_shell_category_view_new (name, filter); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), categoryview, FALSE, TRUE, 0); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "desktop-item-activated", + G_CALLBACK (item_activated_cb), shell); + + gtk_widget_show (categoryview); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-in-event", + G_CALLBACK (category_focus_in), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-out-event", + G_CALLBACK (category_focus_out), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "keynav-failed", + G_CALLBACK (keynav_failed), shell); + + g_hash_table_insert (shell->priv->category_views, g_strdup (name), categoryview); +} + +static void +reload_menu (GnomeControlCenter *shell) +{ + GError *error; + GMenuTreeDirectory *d; + GMenuTreeIter *iter; + GMenuTreeItemType next_type; + + error = NULL; + if (!gmenu_tree_load_sync (shell->priv->menu_tree, &error)) + { + g_warning ("Could not load control center menu: %s", error->message); + g_clear_error (&error); + return; + } + + + d = gmenu_tree_get_root_directory (shell->priv->menu_tree); + iter = gmenu_tree_directory_iter (d); + + while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) + { + if (next_type == GMENU_TREE_ITEM_DIRECTORY) + { + GMenuTreeDirectory *subdir; + const gchar *dir_name; + GMenuTreeIter *sub_iter; + GMenuTreeItemType sub_next_type; + + subdir = gmenu_tree_iter_get_directory (iter); + dir_name = gmenu_tree_directory_get_name (subdir); + + maybe_add_category_view (shell, dir_name); + + /* add the items from this category to the model */ + sub_iter = gmenu_tree_directory_iter (subdir); + while ((sub_next_type = gmenu_tree_iter_next (sub_iter)) != GMENU_TREE_ITEM_INVALID) + { + if (sub_next_type == GMENU_TREE_ITEM_ENTRY) + { + GMenuTreeEntry *item = gmenu_tree_iter_get_entry (sub_iter); + cc_shell_model_add_item (CC_SHELL_MODEL (shell->priv->store), + dir_name, + item); + gmenu_tree_item_unref (item); + } + } + + gmenu_tree_iter_unref (sub_iter); + gmenu_tree_item_unref (subdir); + } + } + + gmenu_tree_iter_unref (iter); +} + +static void +on_menu_changed (GMenuTree *monitor, + GnomeControlCenter *shell) +{ + gtk_list_store_clear (shell->priv->store); + reload_menu (shell); +} + +static void +setup_model (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + gtk_widget_set_margin_top (shell->priv->main_vbox, 8); + gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8); + gtk_widget_set_margin_left (shell->priv->main_vbox, 12); + gtk_widget_set_margin_right (shell->priv->main_vbox, 12); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window))); + + priv->store = (GtkListStore *) cc_shell_model_new (); + priv->category_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->menu_tree = gmenu_tree_new_for_path (MENUDIR "/gnomecc.menu", 0); + + reload_menu (shell); + + g_signal_connect (priv->menu_tree, "changed", G_CALLBACK (on_menu_changed), shell); +} + +static void +load_panel_plugins (GnomeControlCenter *shell) +{ + GList *modules; + + /* only allow this function to be run once to prevent modules being loaded + * twice + */ + if (shell->priv->extension_point) + return; + + /* make sure the base type is registered */ + g_type_from_name ("CcPanel"); + + shell->priv->extension_point + = g_io_extension_point_register (CC_SHELL_PANEL_EXTENSION_POINT); + + /* load all the plugins in the panels directory */ + modules = g_io_modules_load_all_in_directory (PANELS_DIR); + g_list_free (modules); + +} + + +static void +home_button_clicked_cb (GtkButton *button, + GnomeControlCenter *shell) +{ + shell_show_overview_page (shell); +} + +static void +notebook_page_notify_cb (GtkNotebook *notebook, + GParamSpec *spec, + GnomeControlCenterPrivate *priv) +{ + int nat_height; + GtkWidget *child; + + child = notebook_get_selected_page (GTK_WIDGET (notebook)); + + if (child == priv->scrolled_window || child == priv->search_scrolled) + { + gtk_widget_show (W (priv->builder, "search-entry")); + gtk_widget_hide (W (priv->builder, "lock-button")); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + UNITY_FIXED_WIDTH, NULL, &nat_height); + else + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); + } + else + { + gtk_widget_hide (W (priv->builder, "search-entry")); + /* set the scrolled window small so that it doesn't force + the window to be larger than this panel */ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + UNITY_FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + UNITY_FIXED_WIDTH, + nat_height); + } + else { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } + } +} + +/* CcShell implementation */ +static void +_shell_embed_widget_in_header (CcShell *shell, + GtkWidget *widget) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkBox *box; + + /* add to header */ + box = GTK_BOX (W (priv->builder, "topright")); + gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + g_ptr_array_add (priv->custom_widgets, g_object_ref (widget)); +} + +/* CcShell implementation */ +static gboolean +_shell_set_active_panel_from_id (CcShell *shell, + const gchar *start_id, + const gchar **argv, + GError **err) +{ + GtkTreeIter iter; + gboolean iter_valid; + gchar *name = NULL; + gchar *desktop = NULL; + GIcon *gicon = NULL; + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkWidget *old_panel; + + /* When loading the same panel again, just set the argv */ + if (g_strcmp0 (priv->current_panel_id, start_id) == 0) + { + g_object_set (G_OBJECT (priv->current_panel), "argv", argv, NULL); + return TRUE; + } + + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + + /* find the details for this item */ + while (iter_valid) + { + gchar *id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + COL_NAME, &name, + COL_DESKTOP_FILE, &desktop, + COL_GICON, &gicon, + COL_ID, &id, + -1); + + if (id && !strcmp (id, start_id)) + { + g_free (id); + break; + } + else + { + g_free (id); + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + name = NULL; + id = NULL; + desktop = NULL; + gicon = NULL; + } + + iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + if (!name) + { + g_warning ("Could not find settings panel \"%s\"", start_id); + } + else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop, + name, gicon) == FALSE) + { + /* Failed to activate the panel for some reason */ + old_panel = priv->current_panel_box; + priv->current_panel_box = NULL; + notebook_select_page (priv->notebook, priv->scrolled_window); + if (old_panel) + notebook_remove_page (priv->notebook, old_panel); + } + else + { + priv->current_panel_id = g_strdup (start_id); + } + + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + return TRUE; +} + +static GtkWidget * +_shell_get_toplevel (CcShell *shell) +{ + return GNOME_CONTROL_CENTER (shell)->priv->window; +} + +/* GObject Implementation */ +static void +gnome_control_center_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_dispose (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + g_free (priv->current_panel_id); + + if (priv->custom_widgets) + { + g_ptr_array_unref (priv->custom_widgets); + priv->custom_widgets = NULL; + } + if (priv->window) + { + gtk_widget_destroy (priv->window); + priv->window = NULL; + + /* destroying the window will destroy its children */ + priv->notebook = NULL; + priv->search_entry = NULL; + priv->search_view = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->store) + { + g_object_unref (priv->store); + priv->store = NULL; + } + + if (priv->search_filter) + { + g_object_unref (priv->search_filter); + priv->search_filter = NULL; + } + + + G_OBJECT_CLASS (gnome_control_center_parent_class)->dispose (object); +} + +static void +gnome_control_center_finalize (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + if (priv->filter_string) + { + g_free (priv->filter_string); + priv->filter_string = NULL; + } + + if (priv->default_window_title) + { + g_free (priv->default_window_title); + priv->default_window_title = NULL; + } + + if (priv->default_window_icon) + { + g_free (priv->default_window_icon); + priv->default_window_icon = NULL; + } + + if (priv->menu_tree) + { + g_signal_handlers_disconnect_by_func (priv->menu_tree, + G_CALLBACK (on_menu_changed), object); + g_object_unref (priv->menu_tree); + } + + if (priv->category_views) + { + g_hash_table_destroy (priv->category_views); + } + + G_OBJECT_CLASS (gnome_control_center_parent_class)->finalize (object); +} + +static void +gnome_control_center_class_init (GnomeControlCenterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcShellClass *shell_class = CC_SHELL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GnomeControlCenterPrivate)); + + object_class->get_property = gnome_control_center_get_property; + object_class->set_property = gnome_control_center_set_property; + object_class->dispose = gnome_control_center_dispose; + object_class->finalize = gnome_control_center_finalize; + + shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id; + shell_class->embed_widget_in_header = _shell_embed_widget_in_header; + shell_class->get_toplevel = _shell_get_toplevel; +} + +static gboolean +window_key_press_event (GtkWidget *win, + GdkEventKey *event, + GnomeControlCenter *self) +{ + GdkKeymap *keymap; + gboolean retval; + GdkModifierType state; + + if (event->state == 0) + return FALSE; + + retval = FALSE; + state = event->state; + keymap = gdk_keymap_get_default (); + gdk_keymap_add_virtual_modifiers (keymap, &state); + state = state & gtk_accelerator_get_default_mod_mask (); + + if (state == GDK_CONTROL_MASK) + { + switch (event->keyval) + { + case GDK_KEY_s: + case GDK_KEY_S: + case GDK_KEY_f: + case GDK_KEY_F: + if (gtk_widget_get_visible (self->priv->search_entry)) + { + gtk_widget_grab_focus (self->priv->search_entry); + retval = TRUE; + } + break; + case GDK_KEY_Q: + case GDK_KEY_q: + g_object_unref (self); + retval = TRUE; + break; + case GDK_KEY_W: + case GDK_KEY_w: + if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) + shell_show_overview_page (self); + retval = TRUE; + break; + } + } + return retval; +} + +static gint +get_monitor_height (GnomeControlCenter *self) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* We cannot use workarea here, as this wouldn't + * be updated when we read it after a monitors-changed signal */ + screen = gtk_widget_get_screen (self->priv->window); + gdk_screen_get_monitor_geometry (screen, self->priv->monitor_num, &rect); + + return rect.height; +} + +static gboolean +update_monitor_number (GnomeControlCenter *self) +{ + gboolean changed = FALSE; + GtkWidget *widget; + GdkScreen *screen; + GdkWindow *window; + int monitor; + + widget = self->priv->window; + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (widget); + monitor = gdk_screen_get_monitor_at_window (screen, window); + if (self->priv->monitor_num != monitor) + { + self->priv->monitor_num = monitor; + changed = TRUE; + } + + return changed; +} + +static CcSmallScreen +is_small (GnomeControlCenter *self) +{ + if (get_monitor_height (self) <= FIXED_HEIGHT) + return SMALL_SCREEN_TRUE; + return SMALL_SCREEN_FALSE; +} + +static void +update_small_screen_settings (GnomeControlCenter *self) +{ + CcSmallScreen small; + + update_monitor_number (self); + small = is_small (self); + + if (small == SMALL_SCREEN_TRUE) + { + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), TRUE); + + if (self->priv->small_screen != small) + gtk_window_maximize (GTK_WINDOW (self->priv->window)); + } + else + { + if (self->priv->small_screen != small) + gtk_window_unmaximize (GTK_WINDOW (self->priv->window)); + + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), FALSE); + } + + self->priv->small_screen = small; + + /* And update the minimum sizes */ + notebook_page_notify_cb (GTK_NOTEBOOK (self->priv->notebook), NULL, self->priv); +} + +static gboolean +main_window_configure_cb (GtkWidget *widget, + GdkEvent *event, + GnomeControlCenter *self) +{ + update_small_screen_settings (self); + return FALSE; +} + +static void +application_set_cb (GObject *object, + GParamSpec *pspec, + GnomeControlCenter *self) +{ + /* update small screen settings now - to avoid visible resizing, we want + * to do it before showing the window, and GtkApplicationWindow cannot be + * realized unless its application property has been set */ + if (gtk_window_get_application (GTK_WINDOW (self->priv->window))) + { + gtk_widget_realize (self->priv->window); + update_small_screen_settings (self); + } +} + +static void +monitors_changed_cb (GdkScreen *screen, + GnomeControlCenter *self) +{ + /* We reset small_screen_set to make sure that the + * window gets maximised if need be, in update_small_screen_settings() */ + self->priv->small_screen = SMALL_SCREEN_UNSET; + update_small_screen_settings (self); +} + +static void +gnome_control_center_init (GnomeControlCenter *self) +{ + GError *err = NULL; + GnomeControlCenterPrivate *priv; + GdkScreen *screen; + GtkWidget *widget; + + priv = self->priv = CONTROL_CENTER_PRIVATE (self); + +#ifdef HAVE_CHEESE + if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + { + g_critical ("Clutter-GTK init failed"); + return; + } +#endif /* HAVE_CHEESE */ + + priv->monitor_num = -1; + self->priv->small_screen = SMALL_SCREEN_UNSET; + + /* load the user interface */ + priv->builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (priv->builder, UIDIR "/shell.ui", &err)) + { + g_critical ("Could not build interface: %s", err->message); + g_error_free (err); + + return; + } + + /* connect various signals */ + priv->window = W (priv->builder, "main-window"); + gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (priv->window), TRUE); + screen = gtk_widget_get_screen (priv->window); + g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self); + g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self); + g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self); + g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self); + g_signal_connect_after (priv->window, "key_press_event", + G_CALLBACK (window_key_press_event), self); + + priv->notebook = W (priv->builder, "notebook"); + + /* Main scrolled window */ + priv->scrolled_window = W (priv->builder, "scrolledwindow1"); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); + else + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + priv->main_vbox = W (priv->builder, "main-vbox"); + g_signal_connect (priv->notebook, "notify::page", + G_CALLBACK (notebook_page_notify_cb), priv); + + priv->nav_bar = cc_shell_nav_bar_new (); + widget = W (priv->builder, "hbox1"); + gtk_box_pack_start (GTK_BOX (widget), priv->nav_bar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (widget), priv->nav_bar, 0); + gtk_widget_show (priv->nav_bar); + + g_signal_connect (priv->nav_bar, + "home-clicked", G_CALLBACK (home_button_clicked_cb), self); + + /* keep a list of custom widgets to unload on panel change */ + priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* load the available settings panels */ + setup_model (self); + + /* load the panels that are implemented as plugins */ + load_panel_plugins (self); + + /* setup search functionality */ + setup_search (self); + + setup_lock (self); + + /* store default window title and name */ + priv->default_window_title = g_strdup (gtk_window_get_title (GTK_WINDOW (priv->window))); + priv->default_window_icon = g_strdup (gtk_window_get_icon_name (GTK_WINDOW (priv->window))); + + notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv); +} + +GnomeControlCenter * +gnome_control_center_new (void) +{ + return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL); +} + +void +gnome_control_center_present (GnomeControlCenter *center) +{ + gtk_window_present (GTK_WINDOW (center->priv->window)); +} + +void +gnome_control_center_show (GnomeControlCenter *center, + GtkApplication *app) +{ + gtk_window_set_application (GTK_WINDOW (center->priv->window), app); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window))); +} diff -Nru gnome-control-center-3.6.3/.pc/unity_no_zoom_controls.patch/panels/universal-access/cc-ua-panel.c gnome-control-center-3.6.3/.pc/unity_no_zoom_controls.patch/panels/universal-access/cc-ua-panel.c --- gnome-control-center-3.6.3/.pc/unity_no_zoom_controls.patch/panels/universal-access/cc-ua-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/unity_no_zoom_controls.patch/panels/universal-access/cc-ua-panel.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,704 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2008 William Jon McCann + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Thomas Wood + * Rodrigo Moya + * + */ + +#include + +#include +#include +#include +#include "cc-ua-panel.h" + +#include "zoom-options.h" + +#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w) + +#define DPI_FACTOR_LARGE 1.25 +#define DPI_FACTOR_NORMAL 1.0 + +#define HIGH_CONTRAST_THEME "HighContrast" +#define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" +#define KEY_GTK_THEME "gtk-theme" +#define KEY_ICON_THEME "icon-theme" +#define KEY_WM_THEME "theme" + +CC_PANEL_REGISTER (CcUaPanel, cc_ua_panel) + +#define UA_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_UA_PANEL, CcUaPanelPrivate)) + +struct _CcUaPanelPrivate +{ + GtkBuilder *builder; + GSettings *wm_settings; + GSettings *interface_settings; + GSettings *kb_settings; + GSettings *mouse_settings; + GSettings *application_settings; + GSettings *mediakeys_settings; + + ZoomOptions *zoom_options; + guint shell_watch_id; +}; + + +static void +cc_ua_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_ua_panel_dispose (GObject *object) +{ + CcUaPanelPrivate *priv = CC_UA_PANEL (object)->priv; + + if (priv->shell_watch_id) + { + g_bus_unwatch_name (priv->shell_watch_id); + priv->shell_watch_id = 0; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->wm_settings) + { + g_object_unref (priv->wm_settings); + priv->wm_settings = NULL; + } + + if (priv->interface_settings) + { + g_object_unref (priv->interface_settings); + priv->interface_settings = NULL; + } + + if (priv->kb_settings) + { + g_object_unref (priv->kb_settings); + priv->kb_settings = NULL; + } + + if (priv->mouse_settings) + { + g_object_unref (priv->mouse_settings); + priv->mouse_settings = NULL; + } + + if (priv->application_settings) + { + g_object_unref (priv->application_settings); + priv->application_settings = NULL; + } + + if (priv->mediakeys_settings) + { + g_object_unref (priv->mediakeys_settings); + priv->mediakeys_settings = NULL; + } + + if (priv->zoom_options) + { + g_object_unref (priv->zoom_options); + priv->zoom_options = NULL; + } + + G_OBJECT_CLASS (cc_ua_panel_parent_class)->dispose (object); +} + +static void +cc_ua_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_ua_panel_parent_class)->finalize (object); +} + +static const char * +cc_ua_panel_get_help_uri (CcPanel *panel) +{ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + return "help:ubuntu-help/a11y"; + else + return "help:gnome-help/a11y"; +} + +static void +cc_ua_panel_class_init (CcUaPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcUaPanelPrivate)); + + panel_class->get_help_uri = cc_ua_panel_get_help_uri; + + object_class->get_property = cc_ua_panel_get_property; + object_class->set_property = cc_ua_panel_set_property; + object_class->dispose = cc_ua_panel_dispose; + object_class->finalize = cc_ua_panel_finalize; +} + +static gchar *sticky_keys_section[] = { + "typing_sticky_keys_disable_two_keys_checkbutton", + "typing_sticky_keys_beep_modifier_checkbutton", + NULL +}; + +static gchar *slow_keys_section[]= { + "typing_slowkeys_delay_box", + "typing_slow_keys_beeb_box", + NULL +}; + +static gchar *bounce_keys_section[] = { + "typing_bouncekeys_delay_box", + "typing_bounce_keys_beep_rejected_checkbutton", + NULL +}; + +static gchar *secondary_click_section[] = { + "pointing_secondary_click_scale_box", + NULL +}; + +static gchar *dwell_click_section[] = { + "pointing_hover_click_delay_scale_box", + "pointing_hover_click_threshold_scale_box", + NULL +}; + +static gchar *visual_alerts_section[] = { + "hearing_test_flash_button", + "hearing_flash_window_title_button", + "hearing_flash_screen_button", + NULL +}; + +/* zoom options dialog */ +static void +zoom_options_launch_cb (GtkWidget *options_button, CcUaPanel *self) +{ + if (self->priv->zoom_options == NULL) + self->priv->zoom_options = zoom_options_new (); + + if (self->priv->zoom_options != NULL) + zoom_options_set_parent (self->priv->zoom_options, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); +} + +static void +cc_ua_panel_section_switched (GObject *object, + GParamSpec *pspec, + GtkBuilder *builder) +{ + GtkWidget *w; + gboolean enabled; + gchar **widgets, **s; + + widgets = g_object_get_data (object, "section-widgets"); + + g_object_get (object, "active", &enabled, NULL); + + for (s = widgets; *s; s++) + { + w = WID (builder, *s); + gtk_widget_set_sensitive (w, enabled); + } +} + +static void +settings_on_off_editor_new (CcUaPanelPrivate *priv, + GSettings *settings, + const gchar *key, + GtkWidget *widget, + gchar **section) +{ + /* set data to enable/disable the section this on/off switch controls */ + if (section) + { + g_object_set_data (G_OBJECT (widget), "section-widgets", section); + g_signal_connect (widget, "notify::active", + G_CALLBACK (cc_ua_panel_section_switched), + priv->builder); + } + + /* set up the boolean editor */ + g_settings_bind (settings, key, widget, "active", G_SETTINGS_BIND_DEFAULT); +} + +/* seeing section */ + +static void +cc_ua_panel_set_shortcut_label (CcUaPanel *self, + const char *label, + const char *key) +{ + GtkWidget *widget; + char *value; + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + widget = WID (self->priv->builder, label); + value = g_settings_get_string (self->priv->mediakeys_settings, key); + + if (value == NULL || *value == '\0') { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) { + gtk_label_set_text (GTK_LABEL (widget), _("No shortcut set")); + g_free (value); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + g_free (value); + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +shell_vanished_cb (GDBusConnection *connection, + const gchar *name, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_hide (WID (priv->builder, "zoom_label_box")); + gtk_widget_hide (WID (priv->builder, "zoom_value_box")); +} + +static void +shell_appeared_cb (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + gtk_widget_show (WID (priv->builder, "zoom_label_box")); + gtk_widget_show (WID (priv->builder, "zoom_value_box")); +} + +static gboolean +get_large_text_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + gdouble factor; + gboolean large; + + factor = g_variant_get_double (variant); + large = factor > DPI_FACTOR_NORMAL; + g_value_set_boolean (value, large); + + return TRUE; +} + +static GVariant * +set_large_text_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean large; + GSettings *settings = user_data; + GVariant *ret = NULL; + + large = g_value_get_boolean (value); + if (large) + ret = g_variant_new_double (DPI_FACTOR_LARGE); + else + g_settings_reset (settings, KEY_TEXT_SCALING_FACTOR); + + return ret; +} + +static gboolean +get_contrast_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + const char *theme; + gboolean hc; + + theme = g_variant_get_string (variant, NULL); + hc = (g_strcmp0 (theme, HIGH_CONTRAST_THEME) == 0); + g_value_set_boolean (value, hc); + + return TRUE; +} + +static GVariant * +set_contrast_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + gboolean hc; + CcUaPanel *self = user_data; + CcUaPanelPrivate *priv = self->priv; + GVariant *ret = NULL; + + hc = g_value_get_boolean (value); + if (hc) + { + ret = g_variant_new_string (HIGH_CONTRAST_THEME); + g_settings_set_string (priv->interface_settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); + + g_settings_set_string (priv->wm_settings, KEY_WM_THEME, HIGH_CONTRAST_THEME); + } + else + { + g_settings_reset (priv->interface_settings, KEY_GTK_THEME); + g_settings_reset (priv->interface_settings, KEY_ICON_THEME); + + g_settings_reset (priv->wm_settings, KEY_WM_THEME); + } + + return ret; +} + +static void +cc_ua_panel_init_seeing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + + g_settings_bind_with_mapping (priv->interface_settings, KEY_GTK_THEME, + WID (priv->builder, "seeing_contrast_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_contrast_mapping, + set_contrast_mapping, + self, + NULL); + g_settings_bind_with_mapping (priv->interface_settings, KEY_TEXT_SCALING_FACTOR, + WID (priv->builder, "seeing_large_text_switch"), + "active", G_SETTINGS_BIND_DEFAULT, + get_large_text_mapping, + set_large_text_mapping, + priv->interface_settings, + NULL); + + g_settings_bind (priv->kb_settings, "togglekeys-enable", + WID (priv->builder, "seeing_toggle_keys_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + priv->shell_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Shell", + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) shell_appeared_cb, + (GBusNameVanishedCallback) shell_vanished_cb, + self, + NULL); + g_signal_connect (WID (priv->builder, "seeing_zoom_preferences_button"), + "clicked", + G_CALLBACK (zoom_options_launch_cb), self); + g_settings_bind (priv->application_settings, "screen-magnifier-enabled", + WID (priv->builder, "seeing_zoom_switch"), "active", + G_SETTINGS_BIND_DEFAULT); + + settings_on_off_editor_new (priv, priv->application_settings, + "screen-reader-enabled", + WID (priv->builder, "seeing_reader_switch"), + NULL); + + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_enable_keybinding_label", "magnifier"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_in_keybinding_label", "magnifier-zoom-in"); + cc_ua_panel_set_shortcut_label (self, "seeing_zoom_out_keybinding_label", "magnifier-zoom-out"); + cc_ua_panel_set_shortcut_label (self, "seeing_reader_enable_keybinding_label", "screenreader"); +} + + +/* hearing/sound section */ +static void +visual_bell_type_notify_cb (GSettings *settings, + const gchar *key, + CcUaPanel *panel) +{ + GtkWidget *widget; + GDesktopVisualBellType type; + + type = g_settings_get_enum (panel->priv->wm_settings, "visual-bell-type"); + + if (type == G_DESKTOP_VISUAL_BELL_FRAME_FLASH) + widget = WID (panel->priv->builder, "hearing_flash_window_title_button"); + else + widget = WID (panel->priv->builder, "hearing_flash_screen_button"); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); +} + +static void +visual_bell_type_toggle_cb (GtkWidget *button, + CcUaPanel *panel) +{ + gboolean frame_flash; + GDesktopVisualBellType type; + + frame_flash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (frame_flash) + type = G_DESKTOP_VISUAL_BELL_FRAME_FLASH; + else + type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH; + g_settings_set_enum (panel->priv->wm_settings, "visual-bell-type", type); +} + +static gboolean +hearing_sound_preferences_clicked (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_hearing (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* set the initial visual bell values */ + visual_bell_type_notify_cb (NULL, NULL, self); + + /* and listen */ + w = WID (priv->builder, "hearing_visual_alerts_switch"); + settings_on_off_editor_new (priv, priv->wm_settings, "visual-bell", w, visual_alerts_section); + + g_signal_connect (priv->wm_settings, "changed::visual-bell-type", + G_CALLBACK (visual_bell_type_notify_cb), self); + g_signal_connect (WID (priv->builder, "hearing_flash_window_title_button"), + "toggled", G_CALLBACK (visual_bell_type_toggle_cb), self); + + /* test flash */ + g_signal_connect (WID (priv->builder, "hearing_test_flash_button"), + "clicked", G_CALLBACK (gdk_beep), NULL); + + g_signal_connect (WID (priv->builder, "hearing_sound_preferences_link"), + "activate-link", + G_CALLBACK (hearing_sound_preferences_clicked), self); +} + +/* typing/keyboard section */ + +static void +cc_ua_panel_init_keyboard (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* Typing assistant (on-screen keyboard) */ + w = WID (priv->builder, "typing_assistant_switch"); + g_settings_bind (priv->application_settings, "screen-keyboard-enabled", + w, "active", G_SETTINGS_BIND_DEFAULT); + + /* enable shortcuts */ + w = WID (priv->builder, "typing_keyboard_toggle_switch"); + g_settings_bind (priv->kb_settings, "enable", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* sticky keys */ + w = WID (priv->builder, "typing_sticky_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "stickykeys-enable", w, sticky_keys_section); + + w = WID (priv->builder, "typing_sticky_keys_disable_two_keys_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-two-key-off", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + w = WID (priv->builder, "typing_sticky_keys_beep_modifier_checkbutton"); + g_settings_bind (priv->kb_settings, "stickykeys-modifier-beep", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); + + /* slow keys */ + w = WID (priv->builder, "typing_slow_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "slowkeys-enable", w, slow_keys_section); + + w = WID (priv->builder, "typing_slowkeys_delay_scale"); + g_settings_bind (priv->kb_settings, "slowkeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_pressed_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-press", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_accepted_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-accept", w, "active", G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_slow_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "slowkeys-beep-reject", w, "active", G_SETTINGS_BIND_DEFAULT); + + /* bounce keys */ + w = WID (priv->builder, "typing_bounce_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "bouncekeys-enable", w, bounce_keys_section); + + w = WID (priv->builder, "typing_bouncekeys_delay_scale"); + g_settings_bind (priv->kb_settings, "bouncekeys-delay", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "typing_bounce_keys_beep_rejected_checkbutton"); + g_settings_bind (priv->kb_settings, "bouncekeys-beep-reject", w, "active", G_SETTINGS_BIND_NO_SENSITIVITY); +} + +/* mouse/pointing & clicking section */ +static gboolean +pointing_mouse_preferences_clicked_cb (GtkButton *button, + CcUaPanel *panel) +{ + CcShell *shell; + + shell = cc_panel_get_shell (CC_PANEL (panel)); + cc_shell_set_active_panel_from_id (shell, "mouse", NULL, NULL); + + return TRUE; +} + +static void +cc_ua_panel_init_mouse (CcUaPanel *self) +{ + CcUaPanelPrivate *priv = self->priv; + GtkWidget *w; + + /* mouse keys */ + w = WID (priv->builder, "pointing_mouse_keys_switch"); + settings_on_off_editor_new (priv, priv->kb_settings, "mousekeys-enable", w, NULL); + + /* simulated secondary click */ + w = WID (priv->builder, "pointing_second_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "secondary-click-enabled", w, secondary_click_section); + + w = WID (priv->builder, "pointing_secondary_click_delay_scale"); + g_settings_bind (priv->mouse_settings, "secondary-click-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* dwell click */ + w = WID (priv->builder, "pointing_hover_click_switch"); + settings_on_off_editor_new (priv, priv->mouse_settings, "dwell-click-enabled", w, dwell_click_section); + + w = WID (priv->builder, "pointing_dwell_delay_scale"); + g_settings_bind (priv->mouse_settings, "dwell-time", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + w = WID (priv->builder, "pointing_dwell_threshold_scale"); + g_settings_bind (priv->mouse_settings, "dwell-threshold", + gtk_range_get_adjustment (GTK_RANGE (w)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* mouse preferences button */ + g_signal_connect (WID (priv->builder, "pointing_mouse_preferences_link"), + "activate-link", + G_CALLBACK (pointing_mouse_preferences_clicked_cb), self); +} + +static void +cc_ua_panel_init (CcUaPanel *self) +{ + CcUaPanelPrivate *priv; + GtkWidget *widget; + GError *err = NULL; + gchar *objects[] = { "universal_access_box", "contrast_model", + "text_size_model", "slowkeys_delay_adjustment", + "bouncekeys_delay_adjustment", "click_delay_adjustment", + "dwell_time_adjustment", "dwell_threshold_adjustment", + "seeing_sizegroup", "typing_sizegroup", + "pointing_sizegroup", "pointing_sizegroup2", + "pointing_scale_sizegroup", "sizegroup1", + "hearing_sizegroup", + NULL }; + + priv = self->priv = UA_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_objects_from_file (priv->builder, + GNOMECC_UI_DIR "/uap.ui", + objects, + &err); + + if (err) + { + g_warning ("Could not load interface file: %s", err->message); + g_error_free (err); + + g_object_unref (priv->builder); + priv->builder = NULL; + + return; + } + + priv->interface_settings = g_settings_new ("org.gnome.desktop.interface"); + priv->wm_settings = g_settings_new ("org.gnome.desktop.wm.preferences"); + priv->kb_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard"); + priv->mouse_settings = g_settings_new ("org.gnome.desktop.a11y.mouse"); + priv->application_settings = g_settings_new ("org.gnome.desktop.a11y.applications"); + priv->mediakeys_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + + cc_ua_panel_init_keyboard (self); + cc_ua_panel_init_mouse (self); + cc_ua_panel_init_hearing (self); + cc_ua_panel_init_seeing (self); + + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, + "universal_access_box"); + + gtk_container_add (GTK_CONTAINER (self), widget); +} + +void +cc_ua_panel_register (GIOModule *module) +{ + cc_ua_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_UA_PANEL, + "universal-access", 0); +} + diff -Nru gnome-control-center-3.6.3/.pc/.version gnome-control-center-3.6.3/.pc/.version --- gnome-control-center-3.6.3/.pc/.version 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/.version 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru gnome-control-center-3.6.3/.pc/zz_add_fallback_panels_dir.patch/shell/gnome-control-center.c gnome-control-center-3.6.3/.pc/zz_add_fallback_panels_dir.patch/shell/gnome-control-center.c --- gnome-control-center-3.6.3/.pc/zz_add_fallback_panels_dir.patch/shell/gnome-control-center.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/.pc/zz_add_fallback_panels_dir.patch/shell/gnome-control-center.c 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,1469 @@ +/* + * Copyright (c) 2009, 2010 Intel, Inc. + * Copyright (c) 2010 Red Hat, Inc. + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Thomas Wood + */ + + +#include "gnome-control-center.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CHEESE +#include +#endif /* HAVE_CHEESE */ +#define GMENU_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "cc-panel.h" +#include "cc-shell.h" +#include "cc-shell-category-view.h" +#include "cc-shell-model.h" +#include "cc-shell-nav-bar.h" + +G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) + +#define CONTROL_CENTER_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_CONTROL_CENTER, GnomeControlCenterPrivate)) + +#define W(b,x) GTK_WIDGET (gtk_builder_get_object (b, x)) + +/* Use a fixed width for the shell, since resizing horizontally is more awkward + * for the user than resizing vertically + * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ +#define FIXED_WIDTH 740 +#define UNITY_FIXED_WIDTH 850 +#define FIXED_HEIGHT 650 +#define SMALL_SCREEN_FIXED_HEIGHT 400 + +#define MIN_ICON_VIEW_HEIGHT 300 + +typedef enum { + SMALL_SCREEN_UNSET, + SMALL_SCREEN_TRUE, + SMALL_SCREEN_FALSE +} CcSmallScreen; + +struct _GnomeControlCenterPrivate +{ + GtkBuilder *builder; + GtkWidget *notebook; + GtkWidget *main_vbox; + GtkWidget *scrolled_window; + GtkWidget *search_scrolled; + GtkWidget *current_panel_box; + GtkWidget *current_panel; + char *current_panel_id; + GtkWidget *window; + GtkWidget *search_entry; + GtkWidget *lock_button; + GPtrArray *custom_widgets; + GtkWidget *nav_bar; + + GMenuTree *menu_tree; + GtkListStore *store; + GHashTable *category_views; + + GtkTreeModel *search_filter; + GtkWidget *search_view; + gchar *filter_string; + + guint32 last_time; + + GIOExtensionPoint *extension_point; + + gchar *default_window_title; + gchar *default_window_icon; + + int monitor_num; + CcSmallScreen small_screen; +}; + +/* Notebook helpers */ +static GtkWidget * +notebook_get_selected_page (GtkWidget *notebook) +{ + int curr; + + curr = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); + if (curr == -1) + return NULL; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), curr); +} + +static void +notebook_select_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't select GtkNotebook page %p", page); +} + +static void +notebook_remove_page (GtkWidget *notebook, + GtkWidget *page) +{ + int i, num; + + num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + for (i = 0; i < num; i++) + { + if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i) == page) + { + gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), i); + return; + } + } + + g_warning ("Couldn't find GtkNotebook page to remove %p", page); +} + +static void +notebook_add_page (GtkWidget *notebook, + GtkWidget *page) +{ + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); +} + +static const gchar * +get_icon_name_from_g_icon (GIcon *gicon) +{ + const gchar * const *names; + GtkIconTheme *icon_theme; + int i; + + if (!G_IS_THEMED_ICON (gicon)) + return NULL; + + names = g_themed_icon_get_names (G_THEMED_ICON (gicon)); + icon_theme = gtk_icon_theme_get_default (); + + for (i = 0; names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (icon_theme, names[i])) + return names[i]; + } + + return NULL; +} + +static gboolean +activate_panel (GnomeControlCenter *shell, + const gchar *id, + const gchar **argv, + const gchar *desktop_file, + const gchar *name, + GIcon *gicon) +{ + GnomeControlCenterPrivate *priv = shell->priv; + GType panel_type = G_TYPE_INVALID; + GList *panels, *l; + GtkWidget *box; + const gchar *icon_name; + + /* check if there is an plugin that implements this panel */ + panels = g_io_extension_point_get_extensions (priv->extension_point); + + if (!desktop_file) + return FALSE; + if (!id) + return FALSE; + + for (l = panels; l != NULL; l = l->next) + { + GIOExtension *extension; + const gchar *name; + + extension = l->data; + + name = g_io_extension_get_name (extension); + + if (!g_strcmp0 (name, id)) + { + panel_type = g_io_extension_get_type (extension); + break; + } + } + + if (panel_type == G_TYPE_INVALID) + { + GKeyFile *key_file; + + /* It might be an external panel */ + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, desktop_file, G_KEY_FILE_NONE, NULL)) + { + gchar *command; + + command = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + if (command && command[0]) + { + g_spawn_command_line_async (command, NULL); + g_free (command); + } + } + + g_key_file_free (key_file); + return FALSE; + } + + /* create the panel plugin */ + priv->current_panel = g_object_new (panel_type, "shell", shell, "argv", argv, NULL); + cc_shell_set_active_panel (CC_SHELL (shell), CC_PANEL (priv->current_panel)); + gtk_widget_show (priv->current_panel); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), + cc_panel_get_permission (CC_PANEL (priv->current_panel))); + + box = gtk_alignment_new (0, 0, 1, 1); + gtk_alignment_set_padding (GTK_ALIGNMENT (box), 6, 6, 6, 6); + + gtk_container_add (GTK_CONTAINER (box), priv->current_panel); + + gtk_widget_set_name (box, id); + notebook_add_page (priv->notebook, box); + + /* switch to the new panel */ + gtk_widget_show (box); + notebook_select_page (priv->notebook, box); + cc_shell_nav_bar_show_detail_button (CC_SHELL_NAV_BAR(shell->priv->nav_bar), name); + + /* set the title of the window */ + icon_name = get_icon_name_from_g_icon (gicon); + gtk_window_set_role (GTK_WINDOW (priv->window), id); + gtk_window_set_title (GTK_WINDOW (priv->window), name); + gtk_window_set_default_icon_name (icon_name); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), icon_name); + + priv->current_panel_box = box; + + return TRUE; +} + +static void +_shell_remove_all_custom_widgets (GnomeControlCenterPrivate *priv) +{ + GtkBox *box; + GtkWidget *widget; + guint i; + + /* remove from the header */ + box = GTK_BOX (W (priv->builder, "topright")); + for (i = 0; i < priv->custom_widgets->len; i++) + { + widget = g_ptr_array_index (priv->custom_widgets, i); + gtk_container_remove (GTK_CONTAINER (box), widget); + } + g_ptr_array_set_size (priv->custom_widgets, 0); +} + +static void +shell_show_overview_page (GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + + notebook_select_page (priv->notebook, priv->scrolled_window); + + if (priv->current_panel_box) + notebook_remove_page (priv->notebook, priv->current_panel_box); + priv->current_panel = NULL; + priv->current_panel_box = NULL; + g_clear_pointer (&priv->current_panel_id, g_free); + + /* clear the search text */ + g_free (priv->filter_string); + priv->filter_string = g_strdup (""); + gtk_entry_set_text (GTK_ENTRY (priv->search_entry), ""); + gtk_widget_grab_focus (priv->search_entry); + + gtk_lock_button_set_permission (GTK_LOCK_BUTTON (priv->lock_button), NULL); + + /* reset window title and icon */ + gtk_window_set_role (GTK_WINDOW (priv->window), NULL); + gtk_window_set_title (GTK_WINDOW (priv->window), priv->default_window_title); + gtk_window_set_default_icon_name (priv->default_window_icon); + gtk_window_set_icon_name (GTK_WINDOW (priv->window), + priv->default_window_icon); + + cc_shell_set_active_panel (CC_SHELL (center), NULL); + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + cc_shell_nav_bar_hide_detail_button (CC_SHELL_NAV_BAR (priv->nav_bar)); +} + +void +gnome_control_center_set_overview_page (GnomeControlCenter *center) +{ + shell_show_overview_page (center); +} + +static void +item_activated_cb (CcShellCategoryView *view, + gchar *name, + gchar *id, + gchar *desktop_file, + GnomeControlCenter *shell) +{ + GError *err = NULL; + + if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, &err)) + { + /* TODO: show message to user */ + if (err) + { + g_warning ("Could not active panel \"%s\": %s", id, err->message); + g_error_free (err); + } + } +} + +static gboolean +category_focus_out (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + gtk_icon_view_unselect_all (GTK_ICON_VIEW (view)); + + return FALSE; +} + +static gboolean +category_focus_in (GtkWidget *view, + GdkEventFocus *event, + GnomeControlCenter *shell) +{ + GtkTreePath *path; + + if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL)) + { + path = gtk_tree_path_new_from_indices (0, -1); + gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE); + } + + gtk_icon_view_select_path (GTK_ICON_VIEW (view), path); + gtk_tree_path_free (path); + + return FALSE; +} + +static GList * +get_item_views (GnomeControlCenter *shell) +{ + GList *list, *l; + GList *res; + + list = gtk_container_get_children (GTK_CONTAINER (shell->priv->main_vbox)); + res = NULL; + for (l = list; l; l = l->next) + { + if (!CC_IS_SHELL_CATEGORY_VIEW (l->data)) + continue; + res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data))); + } + + g_list_free (list); + + return res; +} + +static gboolean +keynav_failed (GtkIconView *current_view, + GtkDirectionType direction, + GnomeControlCenter *shell) +{ + GList *views, *v; + GtkIconView *new_view; + GtkTreePath *path; + GtkTreeModel *model; + GtkTreeIter iter; + gint col, c, dist, d; + GtkTreePath *sel; + gboolean res; + + res = FALSE; + + views = get_item_views (shell); + + for (v = views; v; v = v->next) + { + if (v->data == current_view) + break; + } + + if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL) + { + new_view = v->next->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d < dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL) + { + new_view = v->prev->data; + + if (gtk_icon_view_get_cursor (current_view, &path, NULL)) + { + col = gtk_icon_view_get_item_column (current_view, path); + gtk_tree_path_free (path); + + sel = NULL; + dist = 1000; + model = gtk_icon_view_get_model (new_view); + gtk_tree_model_get_iter_first (model, &iter); + do { + path = gtk_tree_model_get_path (model, &iter); + c = gtk_icon_view_get_item_column (new_view, path); + d = ABS (c - col); + if (d <= dist) + { + if (sel) + gtk_tree_path_free (sel); + sel = path; + dist = d; + } + else + gtk_tree_path_free (path); + } while (gtk_tree_model_iter_next (model, &iter)); + + gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE); + gtk_tree_path_free (sel); + } + + gtk_widget_grab_focus (GTK_WIDGET (new_view)); + + res = TRUE; + } + + g_list_free (views); + + return res; +} + +static gboolean +model_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GnomeControlCenterPrivate *priv) +{ + gchar *name, *description; + gchar *needle, *haystack; + gboolean result; + gchar **keywords; + + gtk_tree_model_get (model, iter, + COL_NAME, &name, + COL_DESCRIPTION, &description, + COL_KEYWORDS, &keywords, + -1); + + if (!priv->filter_string || !name) + { + g_free (name); + g_free (description); + g_strfreev (keywords); + return FALSE; + } + + needle = g_utf8_casefold (priv->filter_string, -1); + haystack = g_utf8_casefold (name, -1); + + result = (strstr (haystack, needle) != NULL); + + if (!result && description) + { + gchar *folded; + + folded = g_utf8_casefold (description, -1); + result = (strstr (folded, needle) != NULL); + g_free (folded); + } + + if (!result && keywords) + { + gint i; + gchar *keyword; + + for (i = 0; !result && keywords[i]; i++) + { + keyword = g_utf8_casefold (keywords[i], -1); + result = strstr (keyword, needle) == keyword; + g_free (keyword); + } + } + + g_free (name); + g_free (haystack); + g_free (needle); + g_strfreev (keywords); + + return result; +} + +static gboolean +category_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gchar *filter) +{ + gchar *category; + gboolean result; + + gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1); + + result = (g_strcmp0 (category, filter) == 0); + + g_free (category); + + return result; +} + +static void +search_entry_changed_cb (GtkEntry *entry, + GnomeControlCenter *center) +{ + GnomeControlCenterPrivate *priv = center->priv; + char *str; + + /* if the entry text was set manually (not by the user) */ + if (!g_strcmp0 (priv->filter_string, gtk_entry_get_text (entry))) + return; + + /* Don't re-filter for added trailing or leading spaces */ + str = g_strdup (gtk_entry_get_text (entry)); + g_strstrip (str); + if (!g_strcmp0 (str, priv->filter_string)) + { + g_free (str); + return; + } + + g_free (priv->filter_string); + priv->filter_string = str; + + if (!g_strcmp0 (priv->filter_string, "")) + { + shell_show_overview_page (center); + } + else + { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->search_filter)); + notebook_select_page (priv->notebook, priv->search_scrolled); + } +} + +static gboolean +search_entry_key_press_event_cb (GtkEntry *entry, + GdkEventKey *event, + GnomeControlCenterPrivate *priv) +{ + if (event->keyval == GDK_KEY_Return) + { + GtkTreePath *path; + + path = gtk_tree_path_new_first (); + + priv->last_time = event->time; + + gtk_icon_view_item_activated (GTK_ICON_VIEW (priv->search_view), path); + + gtk_tree_path_free (path); + return TRUE; + } + + if (event->keyval == GDK_KEY_Escape) + { + gtk_entry_set_text (entry, ""); + return TRUE; + } + + return FALSE; +} + +static void +on_search_selection_changed (GtkTreeSelection *selection, + GnomeControlCenter *shell) +{ + GtkTreeModel *model; + GtkTreeIter iter; + char *id = NULL; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + COL_ID, &id, + -1); + + if (id) + cc_shell_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL); + + gtk_tree_selection_unselect_all (selection); + + g_free (id); +} + +static void +setup_search (GnomeControlCenter *shell) +{ + GtkWidget *search_view, *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GnomeControlCenterPrivate *priv = shell->priv; + + g_return_if_fail (priv->store != NULL); + + /* create the search filter */ + priv->search_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->store), + NULL); + + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->search_filter), + (GtkTreeModelFilterVisibleFunc) + model_filter_func, + priv, NULL); + + /* set up the search view */ + priv->search_view = search_view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (search_view), FALSE); + gtk_tree_view_set_model (GTK_TREE_VIEW (search_view), + GTK_TREE_MODEL (priv->search_filter)); + + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, + "follow-state", TRUE, + "xpad", 15, + "ypad", 10, + "stock-size", GTK_ICON_SIZE_DIALOG, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Icon", renderer, + "gicon", COL_GICON, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 0, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", COL_NAME, + NULL); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 15, + NULL); + column = gtk_tree_view_column_new_with_attributes ("Description", renderer, + "text", COL_DESCRIPTION, + NULL); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->search_view), column); + + priv->search_scrolled = W (priv->builder, "search-scrolled-window"); + gtk_container_add (GTK_CONTAINER (priv->search_scrolled), search_view); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->search_view)), + "changed", + G_CALLBACK (on_search_selection_changed), + shell); + + /* setup the search entry widget */ + widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "search-entry"); + priv->search_entry = widget; + priv->filter_string = g_strdup (""); + + g_signal_connect (widget, "changed", G_CALLBACK (search_entry_changed_cb), + shell); + g_signal_connect (widget, "key-press-event", + G_CALLBACK (search_entry_key_press_event_cb), priv); + + gtk_widget_show (priv->search_view); +} + +static void +setup_lock (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + priv->lock_button = W (priv->builder, "lock-button"); +} + +static void +maybe_add_category_view (GnomeControlCenter *shell, + const char *name) +{ + GtkTreeModel *filter; + GtkWidget *categoryview; + + if (g_hash_table_lookup (shell->priv->category_views, name) != NULL) + return; + + if (g_hash_table_size (shell->priv->category_views) > 0) + { + GtkWidget *separator; + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_set_margin_top (separator, 11); + gtk_widget_set_margin_bottom (separator, 10); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), separator, FALSE, FALSE, 0); + gtk_widget_show (separator); + } + + /* create new category view for this category */ + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->priv->store), + NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + (GtkTreeModelFilterVisibleFunc) category_filter_func, + g_strdup (name), g_free); + + categoryview = cc_shell_category_view_new (name, filter); + gtk_box_pack_start (GTK_BOX (shell->priv->main_vbox), categoryview, FALSE, TRUE, 0); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "desktop-item-activated", + G_CALLBACK (item_activated_cb), shell); + + gtk_widget_show (categoryview); + + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-in-event", + G_CALLBACK (category_focus_in), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "focus-out-event", + G_CALLBACK (category_focus_out), shell); + g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)), + "keynav-failed", + G_CALLBACK (keynav_failed), shell); + + g_hash_table_insert (shell->priv->category_views, g_strdup (name), categoryview); +} + +static void +reload_menu (GnomeControlCenter *shell) +{ + GError *error; + GMenuTreeDirectory *d; + GMenuTreeIter *iter; + GMenuTreeItemType next_type; + + error = NULL; + if (!gmenu_tree_load_sync (shell->priv->menu_tree, &error)) + { + g_warning ("Could not load control center menu: %s", error->message); + g_clear_error (&error); + return; + } + + + d = gmenu_tree_get_root_directory (shell->priv->menu_tree); + iter = gmenu_tree_directory_iter (d); + + while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) + { + if (next_type == GMENU_TREE_ITEM_DIRECTORY) + { + GMenuTreeDirectory *subdir; + const gchar *dir_name; + GMenuTreeIter *sub_iter; + GMenuTreeItemType sub_next_type; + + subdir = gmenu_tree_iter_get_directory (iter); + dir_name = gmenu_tree_directory_get_name (subdir); + + maybe_add_category_view (shell, dir_name); + + /* add the items from this category to the model */ + sub_iter = gmenu_tree_directory_iter (subdir); + while ((sub_next_type = gmenu_tree_iter_next (sub_iter)) != GMENU_TREE_ITEM_INVALID) + { + if (sub_next_type == GMENU_TREE_ITEM_ENTRY) + { + GMenuTreeEntry *item = gmenu_tree_iter_get_entry (sub_iter); + cc_shell_model_add_item (CC_SHELL_MODEL (shell->priv->store), + dir_name, + item); + gmenu_tree_item_unref (item); + } + } + + gmenu_tree_iter_unref (sub_iter); + gmenu_tree_item_unref (subdir); + } + } + + gmenu_tree_iter_unref (iter); +} + +static void +on_menu_changed (GMenuTree *monitor, + GnomeControlCenter *shell) +{ + gtk_list_store_clear (shell->priv->store); + reload_menu (shell); +} + +static void +setup_model (GnomeControlCenter *shell) +{ + GnomeControlCenterPrivate *priv = shell->priv; + + gtk_widget_set_margin_top (shell->priv->main_vbox, 8); + gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8); + gtk_widget_set_margin_left (shell->priv->main_vbox, 12); + gtk_widget_set_margin_right (shell->priv->main_vbox, 12); + gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window))); + + priv->store = (GtkListStore *) cc_shell_model_new (); + priv->category_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->menu_tree = gmenu_tree_new_for_path (MENUDIR "/gnomecc.menu", 0); + + reload_menu (shell); + + g_signal_connect (priv->menu_tree, "changed", G_CALLBACK (on_menu_changed), shell); +} + +static void +load_panel_plugins (GnomeControlCenter *shell) +{ + GList *modules; + + /* only allow this function to be run once to prevent modules being loaded + * twice + */ + if (shell->priv->extension_point) + return; + + /* make sure the base type is registered */ + g_type_from_name ("CcPanel"); + + shell->priv->extension_point + = g_io_extension_point_register (CC_SHELL_PANEL_EXTENSION_POINT); + + /* load all the plugins in the panels directory */ + modules = g_io_modules_load_all_in_directory (PANELS_DIR); + g_list_free (modules); + +} + + +static void +home_button_clicked_cb (GtkButton *button, + GnomeControlCenter *shell) +{ + shell_show_overview_page (shell); +} + +static void +notebook_page_notify_cb (GtkNotebook *notebook, + GParamSpec *spec, + GnomeControlCenterPrivate *priv) +{ + int nat_height; + GtkWidget *child; + + child = notebook_get_selected_page (GTK_WIDGET (notebook)); + + if (child == priv->scrolled_window || child == priv->search_scrolled) + { + gtk_widget_show (W (priv->builder, "search-entry")); + gtk_widget_hide (W (priv->builder, "lock-button")); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + UNITY_FIXED_WIDTH, NULL, &nat_height); + else + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); + } + else + { + gtk_widget_hide (W (priv->builder, "search-entry")); + /* set the scrolled window small so that it doesn't force + the window to be larger than this panel */ + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + UNITY_FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + UNITY_FIXED_WIDTH, + nat_height); + } + else { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } + } +} + +/* CcShell implementation */ +static void +_shell_embed_widget_in_header (CcShell *shell, + GtkWidget *widget) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkBox *box; + + /* add to header */ + box = GTK_BOX (W (priv->builder, "topright")); + gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + g_ptr_array_add (priv->custom_widgets, g_object_ref (widget)); +} + +/* CcShell implementation */ +static gboolean +_shell_set_active_panel_from_id (CcShell *shell, + const gchar *start_id, + const gchar **argv, + GError **err) +{ + GtkTreeIter iter; + gboolean iter_valid; + gchar *name = NULL; + gchar *desktop = NULL; + GIcon *gicon = NULL; + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv; + GtkWidget *old_panel; + + /* When loading the same panel again, just set the argv */ + if (g_strcmp0 (priv->current_panel_id, start_id) == 0) + { + g_object_set (G_OBJECT (priv->current_panel), "argv", argv, NULL); + return TRUE; + } + + g_clear_pointer (&priv->current_panel_id, g_free); + + if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") && + !g_strcmp0(start_id, "background")) + start_id = "unity-appearance"; + + /* clear any custom widgets */ + _shell_remove_all_custom_widgets (priv); + + iter_valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + + /* find the details for this item */ + while (iter_valid) + { + gchar *id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + COL_NAME, &name, + COL_DESKTOP_FILE, &desktop, + COL_GICON, &gicon, + COL_ID, &id, + -1); + + if (id && !strcmp (id, start_id)) + { + g_free (id); + break; + } + else + { + g_free (id); + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + name = NULL; + id = NULL; + desktop = NULL; + gicon = NULL; + } + + iter_valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + if (!name) + { + g_warning ("Could not find settings panel \"%s\"", start_id); + } + else if (activate_panel (GNOME_CONTROL_CENTER (shell), start_id, argv, desktop, + name, gicon) == FALSE) + { + /* Failed to activate the panel for some reason */ + old_panel = priv->current_panel_box; + priv->current_panel_box = NULL; + notebook_select_page (priv->notebook, priv->scrolled_window); + if (old_panel) + notebook_remove_page (priv->notebook, old_panel); + } + else + { + priv->current_panel_id = g_strdup (start_id); + } + + g_free (name); + g_free (desktop); + if (gicon) + g_object_unref (gicon); + + return TRUE; +} + +static GtkWidget * +_shell_get_toplevel (CcShell *shell) +{ + return GNOME_CONTROL_CENTER (shell)->priv->window; +} + +/* GObject Implementation */ +static void +gnome_control_center_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gnome_control_center_dispose (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + g_free (priv->current_panel_id); + + if (priv->custom_widgets) + { + g_ptr_array_unref (priv->custom_widgets); + priv->custom_widgets = NULL; + } + if (priv->window) + { + gtk_widget_destroy (priv->window); + priv->window = NULL; + + /* destroying the window will destroy its children */ + priv->notebook = NULL; + priv->search_entry = NULL; + priv->search_view = NULL; + } + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + if (priv->store) + { + g_object_unref (priv->store); + priv->store = NULL; + } + + if (priv->search_filter) + { + g_object_unref (priv->search_filter); + priv->search_filter = NULL; + } + + + G_OBJECT_CLASS (gnome_control_center_parent_class)->dispose (object); +} + +static void +gnome_control_center_finalize (GObject *object) +{ + GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (object)->priv; + + if (priv->filter_string) + { + g_free (priv->filter_string); + priv->filter_string = NULL; + } + + if (priv->default_window_title) + { + g_free (priv->default_window_title); + priv->default_window_title = NULL; + } + + if (priv->default_window_icon) + { + g_free (priv->default_window_icon); + priv->default_window_icon = NULL; + } + + if (priv->menu_tree) + { + g_signal_handlers_disconnect_by_func (priv->menu_tree, + G_CALLBACK (on_menu_changed), object); + g_object_unref (priv->menu_tree); + } + + if (priv->category_views) + { + g_hash_table_destroy (priv->category_views); + } + + G_OBJECT_CLASS (gnome_control_center_parent_class)->finalize (object); +} + +static void +gnome_control_center_class_init (GnomeControlCenterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcShellClass *shell_class = CC_SHELL_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GnomeControlCenterPrivate)); + + object_class->get_property = gnome_control_center_get_property; + object_class->set_property = gnome_control_center_set_property; + object_class->dispose = gnome_control_center_dispose; + object_class->finalize = gnome_control_center_finalize; + + shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id; + shell_class->embed_widget_in_header = _shell_embed_widget_in_header; + shell_class->get_toplevel = _shell_get_toplevel; +} + +static gboolean +window_key_press_event (GtkWidget *win, + GdkEventKey *event, + GnomeControlCenter *self) +{ + GdkKeymap *keymap; + gboolean retval; + GdkModifierType state; + + if (event->state == 0) + return FALSE; + + retval = FALSE; + state = event->state; + keymap = gdk_keymap_get_default (); + gdk_keymap_add_virtual_modifiers (keymap, &state); + state = state & gtk_accelerator_get_default_mod_mask (); + + if (state == GDK_CONTROL_MASK) + { + switch (event->keyval) + { + case GDK_KEY_s: + case GDK_KEY_S: + case GDK_KEY_f: + case GDK_KEY_F: + if (gtk_widget_get_visible (self->priv->search_entry)) + { + gtk_widget_grab_focus (self->priv->search_entry); + retval = TRUE; + } + break; + case GDK_KEY_Q: + case GDK_KEY_q: + g_object_unref (self); + retval = TRUE; + break; + case GDK_KEY_W: + case GDK_KEY_w: + if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) + shell_show_overview_page (self); + retval = TRUE; + break; + } + } + return retval; +} + +static gint +get_monitor_height (GnomeControlCenter *self) +{ + GdkScreen *screen; + GdkRectangle rect; + + /* We cannot use workarea here, as this wouldn't + * be updated when we read it after a monitors-changed signal */ + screen = gtk_widget_get_screen (self->priv->window); + gdk_screen_get_monitor_geometry (screen, self->priv->monitor_num, &rect); + + return rect.height; +} + +static gboolean +update_monitor_number (GnomeControlCenter *self) +{ + gboolean changed = FALSE; + GtkWidget *widget; + GdkScreen *screen; + GdkWindow *window; + int monitor; + + widget = self->priv->window; + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (widget); + monitor = gdk_screen_get_monitor_at_window (screen, window); + if (self->priv->monitor_num != monitor) + { + self->priv->monitor_num = monitor; + changed = TRUE; + } + + return changed; +} + +static CcSmallScreen +is_small (GnomeControlCenter *self) +{ + if (get_monitor_height (self) <= FIXED_HEIGHT) + return SMALL_SCREEN_TRUE; + return SMALL_SCREEN_FALSE; +} + +static void +update_small_screen_settings (GnomeControlCenter *self) +{ + CcSmallScreen small; + + update_monitor_number (self); + small = is_small (self); + + if (small == SMALL_SCREEN_TRUE) + { + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), TRUE); + + if (self->priv->small_screen != small) + gtk_window_maximize (GTK_WINDOW (self->priv->window)); + } + else + { + if (self->priv->small_screen != small) + gtk_window_unmaximize (GTK_WINDOW (self->priv->window)); + + gtk_window_set_resizable (GTK_WINDOW (self->priv->window), FALSE); + } + + self->priv->small_screen = small; + + /* And update the minimum sizes */ + notebook_page_notify_cb (GTK_NOTEBOOK (self->priv->notebook), NULL, self->priv); +} + +static gboolean +main_window_configure_cb (GtkWidget *widget, + GdkEvent *event, + GnomeControlCenter *self) +{ + update_small_screen_settings (self); + return FALSE; +} + +static void +application_set_cb (GObject *object, + GParamSpec *pspec, + GnomeControlCenter *self) +{ + /* update small screen settings now - to avoid visible resizing, we want + * to do it before showing the window, and GtkApplicationWindow cannot be + * realized unless its application property has been set */ + if (gtk_window_get_application (GTK_WINDOW (self->priv->window))) + { + gtk_widget_realize (self->priv->window); + update_small_screen_settings (self); + } +} + +static void +monitors_changed_cb (GdkScreen *screen, + GnomeControlCenter *self) +{ + /* We reset small_screen_set to make sure that the + * window gets maximised if need be, in update_small_screen_settings() */ + self->priv->small_screen = SMALL_SCREEN_UNSET; + update_small_screen_settings (self); +} + +static void +gnome_control_center_init (GnomeControlCenter *self) +{ + GError *err = NULL; + GnomeControlCenterPrivate *priv; + GdkScreen *screen; + GtkWidget *widget; + + priv = self->priv = CONTROL_CENTER_PRIVATE (self); + +#ifdef HAVE_CHEESE + if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + { + g_critical ("Clutter-GTK init failed"); + return; + } +#endif /* HAVE_CHEESE */ + + priv->monitor_num = -1; + self->priv->small_screen = SMALL_SCREEN_UNSET; + + /* load the user interface */ + priv->builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (priv->builder, UIDIR "/shell.ui", &err)) + { + g_critical ("Could not build interface: %s", err->message); + g_error_free (err); + + return; + } + + /* connect various signals */ + priv->window = W (priv->builder, "main-window"); + gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (priv->window), TRUE); + screen = gtk_widget_get_screen (priv->window); + g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self); + g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self); + g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self); + g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self); + g_signal_connect_after (priv->window, "key_press_event", + G_CALLBACK (window_key_press_event), self); + + priv->notebook = W (priv->builder, "notebook"); + + /* Main scrolled window */ + priv->scrolled_window = W (priv->builder, "scrolledwindow1"); + + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); + else + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + priv->main_vbox = W (priv->builder, "main-vbox"); + g_signal_connect (priv->notebook, "notify::page", + G_CALLBACK (notebook_page_notify_cb), priv); + + priv->nav_bar = cc_shell_nav_bar_new (); + widget = W (priv->builder, "hbox1"); + gtk_box_pack_start (GTK_BOX (widget), priv->nav_bar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (widget), priv->nav_bar, 0); + gtk_widget_show (priv->nav_bar); + + g_signal_connect (priv->nav_bar, + "home-clicked", G_CALLBACK (home_button_clicked_cb), self); + + /* keep a list of custom widgets to unload on panel change */ + priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* load the available settings panels */ + setup_model (self); + + /* load the panels that are implemented as plugins */ + load_panel_plugins (self); + + /* setup search functionality */ + setup_search (self); + + setup_lock (self); + + /* store default window title and name */ + priv->default_window_title = g_strdup (gtk_window_get_title (GTK_WINDOW (priv->window))); + priv->default_window_icon = g_strdup (gtk_window_get_icon_name (GTK_WINDOW (priv->window))); + + notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv); +} + +GnomeControlCenter * +gnome_control_center_new (void) +{ + return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL); +} + +void +gnome_control_center_present (GnomeControlCenter *center) +{ + gtk_window_present (GTK_WINDOW (center->priv->window)); +} + +void +gnome_control_center_show (GnomeControlCenter *center, + GtkApplication *app) +{ + gtk_window_set_application (GTK_WINDOW (center->priv->window), app); + gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window))); +} diff -Nru gnome-control-center-3.6.3/po/POTFILES.in gnome-control-center-3.6.3/po/POTFILES.in --- gnome-control-center-3.6.3/po/POTFILES.in 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/po/POTFILES.in 2015-02-22 15:27:39.000000000 +0000 @@ -7,7 +7,7 @@ panels/background/cc-background-item.c panels/background/cc-background-panel.c panels/background/gnome-background-panel.desktop.in.in -panels/bluetooth/bluetooth-properties.desktop.in.in +panels/bluetooth/gnome-bluetooth-panel.desktop.in.in [type: gettext/glade]panels/bluetooth/bluetooth.ui panels/bluetooth/cc-bluetooth-panel.c panels/color/cc-color-panel.c @@ -98,6 +98,9 @@ panels/sound/gvc-speaker-test.c panels/sound/gvc-stream-status-icon.c panels/sound/sound-theme-file-utils.c +panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in +panels/sound-nua/gvc-balance-bar.c +panels/sound-nua/gvc-mixer-dialog.c panels/universal-access/cc-ua-panel.c panels/universal-access/gnome-universal-access-panel.desktop.in.in [type: gettext/glade]panels/universal-access/uap.ui @@ -131,7 +134,10 @@ [type: gettext/glade]panels/wacom/gnome-wacom-properties.ui panels/wacom/gsd-wacom-device.c [type: gettext/glade]panels/wacom/wacom-stylus-page.ui +shell/cc-shell-nav-bar.c shell/control-center.c shell/gnomecc.directory.in shell/gnome-control-center.desktop.in.in [type: gettext/glade]shell/shell.ui +panels/display/cc-rr-labeler.c + diff -Nru gnome-control-center-3.6.3/po/POTFILES.skip gnome-control-center-3.6.3/po/POTFILES.skip --- gnome-control-center-3.6.3/po/POTFILES.skip 2012-05-24 14:20:11.000000000 +0000 +++ gnome-control-center-3.6.3/po/POTFILES.skip 2015-02-22 15:27:39.000000000 +0000 @@ -1,5 +1,5 @@ panels/background/gnome-background-panel.desktop.in -panels/bluetooth/bluetooth-properties.desktop.in +panels/bluetooth/gnome-bluetooth-panel.desktop.in panels/color/gnome-color-panel.desktop.in panels/datetime/gnome-datetime-panel.desktop.in panels/display/gnome-display-panel.desktop.in diff -Nru gnome-control-center-3.6.3/shell/cc-shell-category-view.c gnome-control-center-3.6.3/shell/cc-shell-category-view.c --- gnome-control-center-3.6.3/shell/cc-shell-category-view.c 2012-05-24 14:20:12.000000000 +0000 +++ gnome-control-center-3.6.3/shell/cc-shell-category-view.c 2015-02-22 15:27:39.000000000 +0000 @@ -138,6 +138,7 @@ gtk_icon_view_set_text_column (GTK_ICON_VIEW (iconview), COL_NAME); gtk_icon_view_set_item_width (GTK_ICON_VIEW (iconview), 100); cc_shell_item_view_update_cells (CC_SHELL_ITEM_VIEW (iconview)); + gtk_icon_view_set_columns (GTK_ICON_VIEW (iconview), 7); /* create the header if required */ if (priv->name) diff -Nru gnome-control-center-3.6.3/shell/cc-shell-marshal.list gnome-control-center-3.6.3/shell/cc-shell-marshal.list --- gnome-control-center-3.6.3/shell/cc-shell-marshal.list 2011-11-07 17:22:02.000000000 +0000 +++ gnome-control-center-3.6.3/shell/cc-shell-marshal.list 2015-02-22 15:27:38.000000000 +0000 @@ -1 +1,2 @@ VOID:STRING,STRING,STRING +VOID:VOID diff -Nru gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c --- gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/shell/cc-shell-nav-bar.c 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,150 @@ +/* + * Copyright 2012 Canonical + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Aurélien Gâteau + */ + +#include "cc-shell-nav-bar.h" +#include "cc-shell-marshal.h" + +#include + +G_DEFINE_TYPE (CcShellNavBar, cc_shell_nav_bar, GTK_TYPE_BOX) + +#define SHELL_NAV_BAR_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SHELL_NAV_BAR, CcShellNavBarPrivate)) + +struct _CcShellNavBarPrivate +{ + GtkWidget *home_button; + GtkWidget *detail_button; +}; + +enum +{ + HOME_CLICKED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0,}; + +static void +cc_shell_nav_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_shell_nav_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_shell_nav_bar_dispose (GObject *object) +{ + G_OBJECT_CLASS (cc_shell_nav_bar_parent_class)->dispose (object); +} + +static void +cc_shell_nav_bar_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_shell_nav_bar_parent_class)->finalize (object); +} + +static void +home_button_clicked_cb (GtkButton *button, + CcShellNavBar *bar) +{ + g_signal_emit (bar, signals[HOME_CLICKED], 0); +} + +static void +cc_shell_nav_bar_class_init (CcShellNavBarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcShellNavBarPrivate)); + + object_class->get_property = cc_shell_nav_bar_get_property; + object_class->set_property = cc_shell_nav_bar_set_property; + object_class->dispose = cc_shell_nav_bar_dispose; + object_class->finalize = cc_shell_nav_bar_finalize; + + signals[HOME_CLICKED] = g_signal_new ("home-clicked", + CC_TYPE_SHELL_NAV_BAR, + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + cc_shell_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +cc_shell_nav_bar_init (CcShellNavBar *self) +{ + self->priv = SHELL_NAV_BAR_PRIVATE (self); + self->priv->home_button = gtk_button_new_with_mnemonic (_("_All Settings")); + self->priv->detail_button = gtk_button_new(); + + gtk_box_pack_start (GTK_BOX(self), self->priv->home_button, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX(self), self->priv->detail_button, FALSE, FALSE, 0); + + gtk_widget_show (self->priv->home_button); + + g_signal_connect (self->priv->home_button, "clicked", + G_CALLBACK (home_button_clicked_cb), self); + + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(self)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED); + gtk_style_context_add_class (context, "breadcrumbs"); +} + +GtkWidget * +cc_shell_nav_bar_new (void) +{ + return g_object_new (CC_TYPE_SHELL_NAV_BAR, NULL); +} + +void +cc_shell_nav_bar_show_detail_button (CcShellNavBar *bar, const gchar *label) +{ + gtk_widget_show (bar->priv->detail_button); + gtk_button_set_label (GTK_BUTTON (bar->priv->detail_button), label); +} + +void +cc_shell_nav_bar_hide_detail_button (CcShellNavBar *bar) +{ + gtk_widget_hide (bar->priv->detail_button); +} diff -Nru gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h --- gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/shell/cc-shell-nav-bar.h 2015-02-22 15:27:38.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Canonical + * + * The Control Center 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. + * + * The Control Center 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 the Control Center; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Aurélien Gâteau + */ + +#ifndef _CC_SHELL_NAV_BAR_H +#define _CC_SHELL_NAV_BAR_H + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_SHELL_NAV_BAR cc_shell_nav_bar_get_type() + +#define CC_SHELL_NAV_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + CC_TYPE_SHELL_NAV_BAR, CcShellNavBar)) + +#define CC_SHELL_NAV_BAR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CC_TYPE_SHELL_NAV_BAR, CcShellNavBarClass)) + +#define CC_IS_SHELL_NAV_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + CC_TYPE_SHELL_NAV_BAR)) + +#define CC_IS_SHELL_NAV_BAR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CC_TYPE_SHELL_NAV_BAR)) + +#define CC_SHELL_NAV_BAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CC_TYPE_SHELL_NAV_BAR, CcShellNavBarClass)) + +typedef struct _CcShellNavBar CcShellNavBar; +typedef struct _CcShellNavBarClass CcShellNavBarClass; +typedef struct _CcShellNavBarPrivate CcShellNavBarPrivate; + +struct _CcShellNavBar +{ + GtkBox parent; + + CcShellNavBarPrivate *priv; +}; + +struct _CcShellNavBarClass +{ + GtkBoxClass parent_class; +}; + +GType cc_shell_nav_bar_get_type (void) G_GNUC_CONST; + +GtkWidget *cc_shell_nav_bar_new (void); + +void cc_shell_nav_bar_show_detail_button (CcShellNavBar *bar, const gchar *label); + +void cc_shell_nav_bar_hide_detail_button (CcShellNavBar *bar); + +G_END_DECLS + +#endif /* _CC_SHELL_NAV_BAR_H */ diff -Nru gnome-control-center-3.6.3/shell/control-center.c gnome-control-center-3.6.3/shell/control-center.c --- gnome-control-center-3.6.3/shell/control-center.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/shell/control-center.c 2015-02-22 15:27:38.000000000 +0000 @@ -175,8 +175,12 @@ if (panel) uri = cc_panel_get_help_uri (panel); - - gtk_show_uri (gtk_widget_get_screen (window), + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_show_uri (gtk_widget_get_screen (window), + uri ? uri : "help:ubuntu-help/prefs", + GDK_CURRENT_TIME, NULL); + else + gtk_show_uri (gtk_widget_get_screen (window), uri ? uri : "help:gnome-help/prefs", GDK_CURRENT_TIME, NULL); } diff -Nru gnome-control-center-3.6.3/shell/gnome-control-center.c gnome-control-center-3.6.3/shell/gnome-control-center.c --- gnome-control-center-3.6.3/shell/gnome-control-center.c 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/shell/gnome-control-center.c 2015-02-22 15:27:39.000000000 +0000 @@ -38,6 +38,7 @@ #include "cc-shell.h" #include "cc-shell-category-view.h" #include "cc-shell-model.h" +#include "cc-shell-nav-bar.h" G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL) @@ -50,7 +51,8 @@ * for the user than resizing vertically * Both sizes are defined in https://live.gnome.org/Design/SystemSettings/ */ #define FIXED_WIDTH 740 -#define FIXED_HEIGHT 636 +#define UNITY_FIXED_WIDTH 850 +#define FIXED_HEIGHT 650 #define SMALL_SCREEN_FIXED_HEIGHT 400 #define MIN_ICON_VIEW_HEIGHT 300 @@ -75,6 +77,7 @@ GtkWidget *search_entry; GtkWidget *lock_button; GPtrArray *custom_widgets; + GtkWidget *nav_bar; GMenuTree *menu_tree; GtkListStore *store; @@ -214,7 +217,23 @@ if (panel_type == G_TYPE_INVALID) { - g_warning ("Could not find the loadable module for panel '%s'", id); + GKeyFile *key_file; + + /* It might be an external panel */ + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, desktop_file, G_KEY_FILE_NONE, NULL)) + { + gchar *command; + + command = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + if (command && command[0]) + { + g_spawn_command_line_async (command, NULL); + g_free (command); + } + } + + g_key_file_free (key_file); return FALSE; } @@ -237,6 +256,7 @@ /* switch to the new panel */ gtk_widget_show (box); notebook_select_page (priv->notebook, box); + cc_shell_nav_bar_show_detail_button (CC_SHELL_NAV_BAR(shell->priv->nav_bar), name); /* set the title of the window */ icon_name = get_icon_name_from_g_icon (gicon); @@ -299,6 +319,8 @@ /* clear any custom widgets */ _shell_remove_all_custom_widgets (priv); + + cc_shell_nav_bar_hide_detail_button (CC_SHELL_NAV_BAR (priv->nav_bar)); } void @@ -882,6 +904,9 @@ modules = g_io_modules_load_all_in_directory (PANELS_DIR); g_list_free (modules); + /* hardcoded fallback from pre-multiarching */ + modules = g_io_modules_load_all_in_directory ("/usr/lib/control-center-1/panels"); + g_list_free (modules); } @@ -902,31 +927,41 @@ child = notebook_get_selected_page (GTK_WIDGET (notebook)); - /* make sure the home button is shown on all pages except the overview page */ - if (child == priv->scrolled_window || child == priv->search_scrolled) { - gtk_widget_hide (W (priv->builder, "home-button")); gtk_widget_show (W (priv->builder, "search-entry")); gtk_widget_hide (W (priv->builder, "lock-button")); - gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), - FIXED_WIDTH, NULL, &nat_height); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + UNITY_FIXED_WIDTH, NULL, &nat_height); + else + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->main_vbox), + FIXED_WIDTH, NULL, &nat_height); gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), priv->small_screen == SMALL_SCREEN_TRUE ? SMALL_SCREEN_FIXED_HEIGHT : nat_height); } else { - gtk_widget_show (W (priv->builder, "home-button")); gtk_widget_hide (W (priv->builder, "search-entry")); /* set the scrolled window small so that it doesn't force the window to be larger than this panel */ - gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), - FIXED_WIDTH, NULL, &nat_height); - gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); - gtk_window_resize (GTK_WINDOW (priv->window), - FIXED_WIDTH, - nat_height); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + UNITY_FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + UNITY_FIXED_WIDTH, + nat_height); + } + else { + gtk_widget_get_preferred_height_for_width (GTK_WIDGET (priv->window), + FIXED_WIDTH, NULL, &nat_height); + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (priv->scrolled_window), MIN_ICON_VIEW_HEIGHT); + gtk_window_resize (GTK_WINDOW (priv->window), + FIXED_WIDTH, + nat_height); + } } } @@ -968,6 +1003,10 @@ g_clear_pointer (&priv->current_panel_id, g_free); + if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") && + !g_strcmp0(start_id, "background")) + start_id = "unity-appearance"; + /* clear any custom widgets */ _shell_remove_all_custom_widgets (priv); @@ -1332,6 +1371,7 @@ GError *err = NULL; GnomeControlCenterPrivate *priv; GdkScreen *screen; + GtkWidget *widget; priv = self->priv = CONTROL_CENTER_PRIVATE (self); @@ -1373,13 +1413,22 @@ /* Main scrolled window */ priv->scrolled_window = W (priv->builder, "scrolledwindow1"); - gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); + if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity")) + gtk_widget_set_size_request (priv->scrolled_window, UNITY_FIXED_WIDTH, -1); + else + gtk_widget_set_size_request (priv->scrolled_window, FIXED_WIDTH, -1); priv->main_vbox = W (priv->builder, "main-vbox"); g_signal_connect (priv->notebook, "notify::page", G_CALLBACK (notebook_page_notify_cb), priv); - g_signal_connect (gtk_builder_get_object (priv->builder, "home-button"), - "clicked", G_CALLBACK (home_button_clicked_cb), self); + priv->nav_bar = cc_shell_nav_bar_new (); + widget = W (priv->builder, "hbox1"); + gtk_box_pack_start (GTK_BOX (widget), priv->nav_bar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (widget), priv->nav_bar, 0); + gtk_widget_show (priv->nav_bar); + + g_signal_connect (priv->nav_bar, + "home-clicked", G_CALLBACK (home_button_clicked_cb), self); /* keep a list of custom widgets to unload on panel change */ priv->custom_widgets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); diff -Nru gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in --- gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/shell/gnome-control-center.desktop.in.in 2015-02-22 15:27:39.000000000 +0000 @@ -6,7 +6,7 @@ Type=Application StartupNotify=true Categories=GNOME;GTK;System; -OnlyShowIn=GNOME;Unity; +OnlyShowIn=GNOME; X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=gnome-control-center X-GNOME-Bugzilla-Component=shell diff -Nru gnome-control-center-3.6.3/shell/libgnome-control-center.pc.in gnome-control-center-3.6.3/shell/libgnome-control-center.pc.in --- gnome-control-center-3.6.3/shell/libgnome-control-center.pc.in 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-3.6.3/shell/libgnome-control-center.pc.in 2015-02-22 15:27:39.000000000 +0000 @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +extensiondir=@libdir@/control-center-1/panels + +Name: libgnome-control-center +Description: A library to create GNOME Control Center extensions +Version: @VERSION@ +Requires: glib-2.0 gio-2.0 gtk+-3.0 +Libs: -L${libdir} -lgnome-control-center +Cflags: -I${includedir}/gnome-control-center-1 diff -Nru gnome-control-center-3.6.3/shell/Makefile.am gnome-control-center-3.6.3/shell/Makefile.am --- gnome-control-center-3.6.3/shell/Makefile.am 2012-10-01 09:39:00.000000000 +0000 +++ gnome-control-center-3.6.3/shell/Makefile.am 2015-02-22 15:27:39.000000000 +0000 @@ -26,20 +26,50 @@ cc-shell-item-view.h \ cc-shell-model.c \ cc-shell-model.h \ - cc-editable-entry.c \ - cc-editable-entry.h \ - cc-panel.c \ - cc-panel.h \ - cc-shell.c \ - cc-shell.h \ + cc-shell-nav-bar.c \ + cc-shell-nav-bar.h \ $(MARSHAL_FILES) gnome_control_center_LDADD = \ + libgnome-control-center.la \ $(SHELL_LIBS) \ $(CHEESE_LIBS) gnome_control_center_LDFLAGS = -export-dynamic +lib_LTLIBRARIES = libgnome-control-center.la + +libgnome_control_center_include_HEADERS = \ + cc-panel.h \ + cc-shell.h \ + cc-editable-entry.h \ + $(NULL) + +libgnome_control_center_la_SOURCES = \ + cc-panel.c \ + cc-panel.h \ + cc-shell.c \ + cc-shell.h \ + cc-editable-entry.c \ + cc-editable-entry.h \ + $(NULL) + +libgnome_control_center_la_LDFLAGS = \ + -no-undefined \ + -version-info $(LIBGNOMECONTROLCENTER_CURRENT):$(LIBGNOMECONTROLCENTER_REVISION):$(LIBGNOMECONTROLCENTER_AGE) \ + $(NULL) + +libgnome_control_center_la_LIBADD = \ + $(LIBGNOME_CONTROL_CENTER_LIBS) \ + $(NULL) + +libgnome_control_center_la_LIBTOOLFLAGS = --tag=disable-static + +libgnome_control_center_includedir = $(includedir)/gnome-control-center-1/libgnome-control-center + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA=libgnome-control-center.pc + AM_CPPFLAGS = \ -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ -DUIDIR="\"$(uidir)\"" \ @@ -70,6 +100,7 @@ gnome-control-center.desktop.in.in \ gnomecc.directory.in \ gnomecc.menu.in \ + libgnome-control-center.pc.in \ cc-shell-marshal.list DISTCLEANFILES = gnome-control-center.desktop gnome-control-center.desktop.in gnomecc.directory gnomecc.menu diff -Nru gnome-control-center-3.6.3/shell/shell.ui gnome-control-center-3.6.3/shell/shell.ui --- gnome-control-center-3.6.3/shell/shell.ui 2012-11-14 11:42:44.000000000 +0000 +++ gnome-control-center-3.6.3/shell/shell.ui 2015-02-22 15:27:39.000000000 +0000 @@ -34,36 +34,6 @@ True - - True - False - 0 - 1 - none - False - - - False - True - True - True - False - image1 - True - - - All Settings - - - - - - - False - 0 - - - True 1 @@ -93,7 +63,7 @@ - 1 + 0 @@ -129,6 +99,9 @@ True queue none + True @@ -172,13 +145,6 @@ - - vertical - - - - - True False