Description: Add desktop effects tab to the appearance capplet Author: ? Index: gnome-control-center-2.30.0/capplets/appearance/appearance-effects.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-2.30.0/capplets/appearance/appearance-effects.c 2010-04-10 00:21:01.152659047 +0100 @@ -0,0 +1,1089 @@ +/* + * Copyright (C) 2007 Canonical + * Written by Michael Vogt <mvo@ubuntu.com> + * and Mirco Müller <mirco@ubuntu.com> + * All Rights Reserved + * + * Based on desktop-effects.c: + * Desktop Effects. A preference panel for compiz. + * Copyright (C) 2006 Red Hat, Inc. + * Author: Soren Sandmann (sandmann@redhat.com) * + * + * 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 <glib.h> +#include <glib/gstdio.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <gdk/gdkx.h> +#include <X11/extensions/Xcomposite.h> +#include <math.h> +#include <stdlib.h> + +#include "appearance.h" +#include "appearance-effects.h" + +#include "gconf-property-editor.h" + +typedef enum { + COMPIZ, + METACITY +} WindowManager; + +#define WINDOW_MANAGER_KEY "/desktop/gnome/session/required_components/windowmanager" +#define REVERT_COUNT 40 +#define SECONDS_WE_WILL_WAIT_FOR_COMPIZ_TO_START 8 +#define PLUGIN_LIST_KEY "/apps/compiz/general/allscreens/options/active_plugins" +#define NUM_WORKSPACES "/apps/metacity/general/num_workspaces" + +/* helper structure to pass pager data around */ +typedef struct _TraversalChunk { + GConfClient *client; + GArray *numRowsArray; + gint rows; +} TraversalChunk; + +/* possible effects level */ +enum { + NO_EFFECTS, + NORMAL_EFFECTS, + EXTRA_EFFECTS, + CUSTOM_EFFECTS +}; + +/* radio-button names in ui-file */ +static const char *effect_choices[] = { + "no_effects_button", + "normal_effects_button", + "extra_effects_button", + "custom_effects_button" +}; + +/* plugin-set for extra-effects level */ +static const gchar* extra_effects[] = { + "shift", + "wobbly", + NULL +}; + +static gboolean +check_graphics_driver (void) +{ + return system ("jockey-gtk --check-composite") == 0; +} + +static gboolean +check_simple_ccsm (void) +{ + return g_file_test ("/usr/bin/simple-ccsm", G_FILE_TEST_IS_EXECUTABLE); +} + +static void +run_simple_ccsm (GtkButton *widget, + gpointer data) +{ + g_spawn_command_line_async ("/usr/bin/simple-ccsm", NULL); +} + +static GSList * +get_plugins (AppearanceData *app, + GError **err) +{ + return gconf_client_get_list (app->client, + PLUGIN_LIST_KEY, + GCONF_VALUE_STRING, + err); +} + +static gboolean +contains_string (GSList *plugins, + const gchar *needle) +{ + GSList *slist; + + for (slist = plugins; slist != NULL; slist = slist->next) + { + const char *s = slist->data; + + if (s && strcmp (s, needle) == 0) + return TRUE; + } + + return FALSE; +} + + +static void +show_info (const char *text) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", + text); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static gchar* +get_string_value (GConfClient* client, + const gchar* key) +{ + gchar *value = NULL; + GError *error = NULL; + + g_assert (client != NULL); + g_assert (key != NULL); + + value = gconf_client_get_string (client, key, &error); + if (error) + return NULL; + + return value; +} + +static gint +get_int_value (GConfClient* client, + const gchar* key) +{ + gint value = 0; + GError* error = NULL; + + g_assert (client != NULL); + g_assert (key != NULL); + + value = gconf_client_get_int (client, key, &error); + if (error) + return 0; + + return value; +} + +static void +check_for_wnck_entry (gpointer data, + gpointer user_data) +{ + gchar *appletId = (gchar*) data; + TraversalChunk *chunk = (TraversalChunk*) user_data; + GString *propertyPath = NULL; + gchar *value = NULL; + gint rows = 0; + gint position = 0; + + /* get bonobo-id of applet */ + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, "/bonobo_iid"); + value = get_string_value (chunk->client, propertyPath->str); + + /* just exit if no bonobo-id was found */ + if (!value) + { + g_string_free (propertyPath, TRUE); + return; + } + + /* test if it is actually a switcher */ + if (!g_ascii_strncasecmp (value, + "OAFIID:GNOME_WorkspaceSwitcherApplet", + 36)) + { + /* assemble new gconf-path for num_rows gconf-key */ + g_string_free (propertyPath, TRUE); + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, "/position"); + + /* get the value of position */ + position = get_int_value (chunk->client, propertyPath->str); + + if (position > 1) + { + /* assemble new gconf-path for num_rows gconf-key */ + g_string_free (propertyPath, TRUE); + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, + "/prefs/num_rows"); + + /* get the value of rows */ + rows = get_int_value (chunk->client, propertyPath->str); + + if (!chunk->numRowsArray) + chunk->numRowsArray = g_array_new (TRUE, + TRUE, + sizeof (gint)); + + g_array_append_val (chunk->numRowsArray, rows); + } + } + + g_string_free (propertyPath, TRUE); +} + +gboolean +set_int_value (GConfClient *client, + const gchar *key, + gint value) +{ + gboolean result = FALSE; + GError *error = NULL; + + g_assert (client != NULL); + g_assert (key != NULL); + + result = gconf_client_set_int (client, + key, + value, + &error); + + if (error) + return FALSE; + + return result; +} + +static void +set_wnck_entry (gpointer data, + gpointer user_data) +{ + gchar *appletId = (gchar*) data; + TraversalChunk *chunk = (TraversalChunk*) user_data; + GString *propertyPath = NULL; + gchar *value = NULL; + gint position = 0; + + /* get bonobo-id of applet */ + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, "/bonobo_iid"); + value = get_string_value (chunk->client, propertyPath->str); + + /* just exit if no bonobo-id was found */ + if (!value) + { + g_string_free (propertyPath, TRUE); + return; + } + + /* test if it is actually a switcher */ + if (!g_ascii_strncasecmp (value, + "OAFIID:GNOME_WorkspaceSwitcherApplet", + 36)) + { + /* assemble new gconf-path for applets position gconf-key */ + g_string_free (propertyPath, TRUE); + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, "/position"); + + /* get the value of position */ + position = get_int_value (chunk->client, propertyPath->str); + + /* not the best way to test, if this applet is really active */ + if (position > 1) + { + /* assemble new gconf-path for num_rows gconf-key */ + g_string_free (propertyPath, TRUE); + propertyPath = g_string_new ("/apps/panel/applets/"); + propertyPath = g_string_append (propertyPath, appletId); + propertyPath = g_string_append (propertyPath, + "/prefs/num_rows"); + + /* set the value of rows */ + set_int_value (chunk->client, + propertyPath->str, + chunk->rows); + } + } + + /* cleanup */ + g_string_free (propertyPath, TRUE); +} + +static gint +get_pager_num_rows (GConfClient *client) +{ + GSList *idList = NULL; + TraversalChunk *chunk = NULL; + gint rows = 0; + + /* get ids of all used applets */ + idList = gconf_client_get_list (client, + "/apps/panel/general/applet_id_list", + GCONF_VALUE_STRING, + NULL); + + if (!idList) + return 1; + + /* create and initialize helper-structure */ + chunk = g_new0 (TraversalChunk, 1); + if (!chunk) + { + g_slist_free (idList); + return 1; + } + + chunk->client = client; + + /* search list of applets for wnck-applet */ + g_slist_foreach (idList, + check_for_wnck_entry, + (gpointer) chunk); + + if (chunk->numRowsArray == NULL) + rows = 1; + else + rows = g_array_index (chunk->numRowsArray, gint, 0); + + /* clean up */ + g_slist_free (idList); + if (chunk->numRowsArray) + g_array_free (chunk->numRowsArray, TRUE); + g_free (chunk); + + return rows; +} + +/* sets the number of rows of the first pager-applet found */ +void static +set_pager_num_rows (GConfClient *client, + gint rows) +{ + GSList *idList = NULL; + TraversalChunk *chunk = NULL; + + /* get ids of all used applets */ + idList = gconf_client_get_list (client, + "/apps/panel/general/applet_id_list", + GCONF_VALUE_STRING, + NULL); + + /* if nothing is found at least return 1 to avoid a div. by 0 later */ + if (!idList) + return; + + /* create and initialize helper-structure */ + chunk = g_new0 (TraversalChunk, 1); + if (!chunk) + { + g_slist_free (idList); + return; + } + + chunk->client = client; + chunk->rows = rows; + + /* search list of applets for wnck-applet */ + g_slist_foreach (idList, + set_wnck_entry, + (gpointer) chunk); + + /* clean up */ + g_slist_free (idList); + if (chunk->numRowsArray) + g_array_free (chunk->numRowsArray, TRUE); + g_free (chunk); +} + +static void +apply_settings (AppearanceData *app, + gboolean effects_enabled) +{ + const char *str = effects_enabled? "compiz" : "metacity"; + char *session_file; + gint vsize; + gint hsize; + gint workspaces; + gint rows; + + gconf_client_set_string (app->client, + WINDOW_MANAGER_KEY, + str, + NULL); + + session_file = g_build_filename (g_get_home_dir (), + ".gnome2", + "session", + NULL); + + g_unlink (session_file); + g_free (session_file); + + /* here the whole logic for mapping any N:M workspace-layout from + * metacity to compiz or vice versa is handled, currently only + * implemented for one-screen setups */ + if (effects_enabled) + { + workspaces = get_int_value (app->client, + "/apps/metacity/general/num_workspaces"); + rows = get_pager_num_rows (app->client); + set_int_value (app->client, + "/apps/compiz/general/screen0/options/vsize", + rows); + set_int_value (app->client, + "/apps/compiz/general/screen0/options/hsize", + (gint) ceilf ((gfloat) workspaces / (gfloat) rows)); + set_pager_num_rows (app->client, 1); + } + else if (app->compiz_was_running) + { + vsize = get_int_value (app->client, + "/apps/compiz/general/screen0/options/vsize"); + hsize = get_int_value (app->client, + "/apps/compiz/general/screen0/options/hsize"); + set_int_value (app->client, + "/apps/metacity/general/num_workspaces", + vsize * hsize); + set_pager_num_rows (app->client, vsize); + } +} + +static void +set_busy (GtkWidget *widget, + gboolean busy) +{ + GdkCursor *cursor; + + if (busy) + cursor = gdk_cursor_new (GDK_WATCH); + else + cursor = NULL; + + gdk_window_set_cursor (widget->window, cursor); + + if (cursor) + gdk_cursor_unref (cursor); + + gdk_flush (); +} + + +gchar* +get_current_window_manager (void) +{ + Window *xwindow; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + gchar *name; + + XGetWindowProperty (GDK_DISPLAY (), + GDK_ROOT_WINDOW (), + XInternAtom (GDK_DISPLAY (), + "_NET_SUPPORTING_WM_CHECK", + False), + 0, + G_MAXLONG, + False, + XA_WINDOW, + &type, + &format, + &nitems, + &bytes_after, + (guchar **) &xwindow); + + if (type != XA_WINDOW) + return NULL; + + gdk_error_trap_push (); + XSelectInput (GDK_DISPLAY (), + *xwindow, + StructureNotifyMask | PropertyChangeMask); + XSync (GDK_DISPLAY (), False); + + if (gdk_error_trap_pop ()) + { + XFree (xwindow); + return NULL; + } + + name = NULL; + + gdk_error_trap_push (); + + XGetWindowProperty (GDK_DISPLAY (), + *xwindow, + XInternAtom (GDK_DISPLAY (), + "_NET_WM_NAME", + False), + 0, + G_MAXLONG, + False, + XInternAtom (GDK_DISPLAY (), + "UTF8_STRING", + False), + &type, + &format, + &nitems, + &bytes_after, + (guchar **)&name); + + gdk_display_sync (GDK_DISPLAY ()); + gdk_error_trap_pop (); + XFree (xwindow); + return name; +} + +static gboolean +compiz_started (void) +{ + gboolean result; + gchar *wm = get_current_window_manager (); + + result = wm && strcmp (wm, "compiz") == 0; + g_free (wm); + + return result; +} + +typedef struct TimedDialogInfo { + AppearanceData *app; + GTimer *timer; + GtkWidget *button; +} TimedDialogInfo; + +static WindowManager +current_configured_wm (AppearanceData *app, + GError **err) +{ + GError *tmp = NULL; + + const char *str = gconf_client_get_string (app->client, + WINDOW_MANAGER_KEY, + &tmp); + + if (tmp) + { + g_propagate_error (err, tmp); + return METACITY; + } + + if (str && strcmp (str, "compiz") == 0) + return COMPIZ; + else + return METACITY; +} + +static void +show_error (const GError *err) +{ + GtkWidget *dialog; + + if (!err) + return; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + "%s", + err->message); + + gtk_window_set_title (GTK_WINDOW (dialog), ""); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +struct TimeoutData { + int time; + GtkLabel *label; + GtkDialog *dialog; + gboolean timed_out; +}; + +static gboolean +free_at_idle (gpointer data) +{ + g_free (data); + return FALSE; +} + +static char* +idle_free (char *str) +{ + g_idle_add (free_at_idle, str); + return str; +} + +static char * +timeout_string (int time) +{ + char *str = g_strdup_printf (ngettext ("Testing the new settings. If you don't respond in %d second the previous settings will be restored.", "Testing the new settings. If you don't respond in %d seconds the previous settings will be restored.", time), time); + + return idle_free (str); +} + +static gboolean +save_timeout_callback (gpointer data) +{ + struct TimeoutData *timeData = data; + + timeData->time--; + + if (timeData->time == 0) + { + gtk_dialog_response (timeData->dialog, GTK_RESPONSE_NO); + timeData->timed_out = TRUE; + return FALSE; + } + + gtk_label_set_text (timeData->label, timeout_string (timeData->time)); + + return TRUE; +} + +static gboolean +run_timed_dialog (AppearanceData *app) +{ + GtkWidget *dialog; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *label_sec; + GtkWidget *image; + int res; + struct TimeoutData timeout_data; + guint timeout; + + dialog = gtk_dialog_new (); + gtk_window_set_transient_for (GTK_WINDOW (dialog), + GTK_WINDOW (app->dialog)); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 12); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Keep Settings")); + gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ALWAYS); + + label = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL (label), + idle_free (g_strdup_printf ("<b>%s</b>", + _("Do you want to keep these settings?")))); + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); + + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + label_sec = gtk_label_new (timeout_string (REVERT_COUNT)); + gtk_label_set_line_wrap (GTK_LABEL (label_sec), TRUE); + gtk_label_set_selectable (GTK_LABEL (label_sec), TRUE); + gtk_misc_set_alignment (GTK_MISC (label_sec), 0.0, 0.5); + + hbox = gtk_hbox_new (FALSE, 6); + vbox = gtk_vbox_new (FALSE, 6); + + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), label_sec, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + hbox, + FALSE, + FALSE, + 0); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("Use _previous settings"), + GTK_RESPONSE_NO, + _("_Keep settings"), + GTK_RESPONSE_YES, + NULL); + + gtk_widget_show_all (hbox); + + timeout_data.time = REVERT_COUNT; + timeout_data.label = GTK_LABEL (label_sec); + timeout_data.dialog = GTK_DIALOG (dialog); + timeout_data.timed_out = FALSE; + + timeout = gdk_threads_add_timeout (1000, save_timeout_callback, &timeout_data); + res = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (!timeout_data.timed_out) + g_source_remove (timeout); + + gtk_widget_destroy (dialog); + + return (res == GTK_RESPONSE_YES); +} + +static gboolean +show_dialog_timeout (gpointer data) +{ + TimedDialogInfo *info = data; + gboolean has_compiz; + + gtk_window_present (GTK_WINDOW (info->app->dialog)); + + has_compiz = compiz_started (); + + if (has_compiz || + g_timer_elapsed (info->timer, + NULL) > SECONDS_WE_WILL_WAIT_FOR_COMPIZ_TO_START) + { + if (has_compiz) + { + set_busy (info->app->dialog, FALSE); + + if (run_timed_dialog (info->app)) + apply_settings (info->app, + info->app->desktop_effects_level >= 1); + else + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->button), + TRUE); + } + else + { + GtkWidget *dialog; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->button), + TRUE); + + set_busy (info->app->dialog, FALSE); + + dialog = gtk_message_dialog_new ((GtkWindow*) info->app->dialog, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + _("Desktop effects could not be enabled")); + + gtk_window_set_title (GTK_WINDOW (dialog), ""); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + + gtk_widget_set_sensitive (info->app->dialog, TRUE); + + g_timer_destroy (info->timer); + g_free (info); + + return FALSE; + } + + return TRUE; +} + +static gboolean +start_compiz (AppearanceData *app, + GError **err) +{ + if (!g_spawn_command_line_async ("compiz --replace", err)) + return FALSE; + + app->compiz_running = TRUE; + + return TRUE; +} + +static gboolean +start_metacity (AppearanceData *app, GError **err) +{ + if (!g_spawn_command_line_async ("metacity --replace", err)) + return FALSE; + + app->compiz_running = FALSE; + + return TRUE; +} + +static gboolean +has_composite () +{ + int dummy1; + int dummy2; + + if (XCompositeQueryExtension (GDK_DISPLAY (), &dummy1, &dummy2)) + return TRUE; + + return FALSE; +} + +static void +show_alert (const char *text) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", + text); + + gtk_dialog_run (GTK_DIALOG (dialog)); +} + +static gboolean +are_effects_enabled (AppearanceData* app, + const gchar** effects_list) +{ + int i; + gboolean res = TRUE; + GError *tmp = NULL; + GSList *plugins; + + plugins = get_plugins (app, &tmp); + for (i = 0; effects_list[i] != NULL; i++) + res &= contains_string (plugins, effects_list[i]); + + return res; +} + +static gboolean +reset_plugins (AppearanceData *app) +{ + GError *error = NULL; + + return gconf_client_unset (app->client, PLUGIN_LIST_KEY, &error); +} + +static gboolean +are_normal_effects_enabled (AppearanceData *app) +{ + gboolean res = TRUE; + GError *err = NULL; + GSList *plugins, *default_plugins; + + default_plugins = gconf_value_get_list ( gconf_client_get_default_from_schema (app->client, PLUGIN_LIST_KEY, &err)); + + err = NULL; + plugins = get_plugins (app, &err); + for(;default_plugins; default_plugins = g_slist_next(default_plugins)) + res &= contains_string(plugins, gconf_value_get_string(default_plugins->data)); + + return res; +} + +static gboolean +are_extra_effects_enabled (AppearanceData *app) +{ + return (are_effects_enabled (app, extra_effects) && + are_normal_effects_enabled (app)); +} + +static gint +get_effects_level (AppearanceData *data) +{ + if (data->compiz_running) + { + if (are_extra_effects_enabled (data)) + return EXTRA_EFFECTS; + else if (are_normal_effects_enabled (data)) + return NORMAL_EFFECTS; + else + return CUSTOM_EFFECTS; + } + else + return NO_EFFECTS; +} + +static gboolean +enable_normal_effects (AppearanceData* app) +{ + return reset_plugins (app); +} + +static gboolean +enable_extra_effects (AppearanceData* app) +{ + GError *err = NULL; + GSList *plugins = NULL; + int i; + + reset_plugins (app); + + plugins = get_plugins (app, &err); + for (i = 0; extra_effects[i] != NULL; i++) + plugins = g_slist_append (plugins, + (gchar*) extra_effects[i]); + + err = NULL; + gconf_client_set_list (app->client, + PLUGIN_LIST_KEY, + GCONF_VALUE_STRING, + plugins, + &err); + + return TRUE; +} + +static void +on_effects_toggle (GtkWidget *widget, + gpointer user_data) +{ + AppearanceData *appdata = user_data; + GtkWidget *previously_selected_button; + static gint old_effects_level; + static gboolean do_init = TRUE; + gint i; + GError *err = NULL; + + if (do_init == TRUE) + { + old_effects_level = get_effects_level (appdata); + do_init = FALSE; + } + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + return; + + previously_selected_button = appearance_capplet_get_widget (appdata, + effect_choices [old_effects_level]); + + /* Look for the button which has been selected */ + for (i = 0; i < G_N_ELEMENTS (effect_choices); i++) + { + if (widget == appearance_capplet_get_widget (appdata, + effect_choices [i])) + break; + } + + appdata->desktop_effects_level = i; + + if (appdata->desktop_effects_level >= 1) + { + if (old_effects_level == 0 && check_graphics_driver()) + { + show_info (_("Please run \"Appearance/Desktop Effects\" again after restarting " + "the computer, when the new graphics driver is active.")); + g_signal_handlers_block_by_func (widget, + on_effects_toggle, + appdata); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appearance_capplet_get_widget (appdata, + effect_choices [old_effects_level])), + TRUE); + g_signal_handlers_unblock_by_func (widget, + on_effects_toggle, + appdata); + return; + } + + if (!has_composite ()) + { + show_alert ("The Composite extension is not available"); + return; + } + + if (old_effects_level == 0) + start_compiz (appdata, &err); + + if (appdata->desktop_effects_level == NORMAL_EFFECTS) + enable_normal_effects (appdata); + + if (appdata->desktop_effects_level == EXTRA_EFFECTS) + enable_extra_effects (appdata); + } + else + { + apply_settings (appdata, FALSE); + start_metacity (appdata, &err); + } + + if (err) + { + show_error (err); + + g_signal_handlers_block_by_func (widget, + on_effects_toggle, + appdata); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appearance_capplet_get_widget (appdata, + effect_choices [old_effects_level])), + TRUE); + g_signal_handlers_unblock_by_func (widget, + on_effects_toggle, + appdata); + } + else + { + if (appdata->desktop_effects_level >= 1 && + old_effects_level == 0) + { + TimedDialogInfo *info = g_new0 (TimedDialogInfo, 1); + + info->app = appdata; + info->button = previously_selected_button; + info->timer = g_timer_new (); + + set_busy (info->app->dialog, TRUE); + gtk_widget_set_sensitive (appdata->dialog, FALSE); + + gdk_threads_add_timeout (250, show_dialog_timeout, info); + } + } + + old_effects_level = i; +} + +void +effects_init (AppearanceData *data) +{ + GtkWidget *level_effects_button = NULL; + GtkWidget *hbox_custom_effects = NULL; + WindowManager wm = METACITY; + gint i; + gchar *str = get_current_window_manager (); + if (str && (strcmp (str, "compiz") == 0)) + wm = COMPIZ; + g_free (str); + + data->compiz_running = (wm == COMPIZ); + data->compiz_was_running = (wm == COMPIZ); + data->dialog = appearance_capplet_get_widget (data, "appearance_window"); + + data->desktop_effects_level = get_effects_level (data); + + for (i = 0; i < G_N_ELEMENTS (effect_choices); i++) + { + level_effects_button = appearance_capplet_get_widget (data, + effect_choices[i]); + if (i == data->desktop_effects_level) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (level_effects_button), + TRUE); + + g_signal_connect (level_effects_button, + "toggled", + G_CALLBACK (on_effects_toggle), + data); + } + + hbox_custom_effects = appearance_capplet_get_widget (data, + "hbox_custom_effects"); + if (check_simple_ccsm ()) + { + GtkWidget *button = NULL; + + gtk_widget_show (hbox_custom_effects); + button = appearance_capplet_get_widget (data, + "custom_effects_edit_button"); + g_signal_connect (button, + "clicked", + G_CALLBACK (run_simple_ccsm), + NULL); + } + else + gtk_widget_hide (hbox_custom_effects); +} + Index: gnome-control-center-2.30.0/capplets/appearance/appearance-effects.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gnome-control-center-2.30.0/capplets/appearance/appearance-effects.h 2010-04-10 00:19:11.640173172 +0100 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2007 Canonical + * Written by Michael Vogt <mvo@ubuntu.com> + * All Rights Reserved + * + * 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. + */ + +void effects_init (AppearanceData *data); +gchar* get_current_window_manager (void); Index: gnome-control-center-2.30.0/capplets/appearance/appearance.h =================================================================== --- gnome-control-center-2.30.0.orig/capplets/appearance/appearance.h 2010-04-10 00:19:11.570163577 +0100 +++ gnome-control-center-2.30.0/capplets/appearance/appearance.h 2010-04-10 00:19:11.640173172 +0100 @@ -81,6 +81,12 @@ gchar *revert_monospace_font; gchar *revert_button_layout; + /* effects */ + gboolean compiz_running; + gboolean compiz_was_running; + gint desktop_effects_level; + GtkWidget *dialog; + /* style */ GdkPixbuf *gtk_theme_icon; GdkPixbuf *window_theme_icon; Index: gnome-control-center-2.30.0/capplets/appearance/appearance-main.c =================================================================== --- gnome-control-center-2.30.0.orig/capplets/appearance/appearance-main.c 2010-03-29 15:22:56.000000000 +0100 +++ gnome-control-center-2.30.0/capplets/appearance/appearance-main.c 2010-04-10 00:19:11.640173172 +0100 @@ -21,6 +21,7 @@ #include <glib/gi18n.h> #include "appearance.h" #include "appearance-desktop.h" +#include "appearance-effects.h" #include "appearance-font.h" #include "appearance-themes.h" #include "appearance-style.h" @@ -116,11 +117,19 @@ } } +static void +set_sensitivity (GtkWidget *widget, GtkWidget *warning) +{ + if (widget != warning) + gtk_widget_set_sensitive (widget, FALSE); +} + int main (int argc, char **argv) { AppearanceData *data; GtkWidget *w; + GtkWidget *warning; gchar *install_filename = NULL; gchar *start_page = NULL; @@ -166,6 +175,7 @@ desktop_init (data, (const gchar **) wallpaper_files); g_strfreev (wallpaper_files); font_init (data); + effects_init (data); /* prepare the main window */ w = appearance_capplet_get_widget (data, "appearance_window"); @@ -207,6 +217,34 @@ g_option_context_free (option_context); + warning = appearance_capplet_get_widget (data, "no_compiz_box"); + + if (g_find_program_in_path ("compiz") == NULL) { + GtkWidget *box; + + box = appearance_capplet_get_widget (data, "effects_vbox"); + gtk_container_foreach (GTK_CONTAINER (box), + (GtkCallback) set_sensitivity, warning); + } + else + gtk_widget_hide_all (warning); + + warning = appearance_capplet_get_widget (data, "mutter_box"); + + gchar *wm = get_current_window_manager (); + + if (wm != NULL && strcmp (wm, "Mutter") == 0) { + GtkWidget *box; + + box = appearance_capplet_get_widget (data, "effects_vbox"); + gtk_container_foreach (GTK_CONTAINER (box), + (GtkCallback) set_sensitivity, warning); + } + else + gtk_widget_hide_all (warning); + + g_free (wm); + /* start the mainloop */ gtk_main (); gdk_threads_leave (); Index: gnome-control-center-2.30.0/capplets/appearance/data/appearance.ui =================================================================== --- gnome-control-center-2.30.0.orig/capplets/appearance/data/appearance.ui 2010-03-04 13:49:28.000000000 +0000 +++ gnome-control-center-2.30.0/capplets/appearance/data/appearance.ui 2010-04-10 00:19:11.640173172 +0100 @@ -1549,6 +1549,342 @@ <property name="tab_fill">False</property> </packing> </child> + <child> + <object class="GtkVBox" id="effects_vbox"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="border_width">6</property> + <property name="spacing">18</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkAlignment" id="no_compiz_box"> + <property name="left_padding">26</property> + <property name="visible">True</property> + <child> + <object class="GtkHBox" id="hbox14"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="stock">gtk-dialog-warning</property> + <property name="icon-size">6</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">6</property> + <property name="label" translatable="yes"><b>Compiz is not installed</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + </child> + </object> + <object class="GtkAlignment" id="mutter_box"> + <property name="left_padding">26</property> + <property name="visible">True</property> + <child> + <object class="GtkHBox" id="hbox15"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image5"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="stock">gtk-dialog-warning</property> + <property name="icon-size">6</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label17"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">6</property> + <property name="label" translatable="yes"><b>Mutter is running, can't switch to other effects.</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="no_effects_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <accelerator key="n" modifiers="" signal="activate"/> + <child> + <object class="GtkHBox" id="hbox_no_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkImage" id="image_no_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="pixbuf">/usr/share/gnome-control-center/pixmaps/visual-effects_none.svg</property> + <property name="icon_size">6</property> + </object> + </child> + <child> + <object class="GtkLabel" id="label_desc_no_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="label" translatable="yes"><b>_None:</b> Provides a simple desktop environment without any effects.</property> + <property name="use_markup">True</property> + <property name="use_underline">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="normal_effects_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">no_effects_button</property> + <accelerator key="o" modifiers="" signal="activate"/> + <child> + <object class="GtkHBox" id="hbox_normal_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkImage" id="image_normal_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="pixbuf">/usr/share/gnome-control-center/pixmaps/visual-effects_normal.svg</property> + <property name="icon_size">6</property> + </object> + </child> + <child> + <object class="GtkLabel" id="label_desc_normal_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="label" translatable="yes"><b>N_ormal:</b> Provides improved usability and good balance between attractiveness and moderate performance requirements.</property> + <property name="use_markup">True</property> + <property name="use_underline">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="extra_effects_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">no_effects_button</property> + <accelerator key="x" modifiers="" signal="activate"/> + <child> + <object class="GtkHBox" id="hbox_extra_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkImage" id="image_extra_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="pixbuf">/usr/share/gnome-control-center/pixmaps/visual-effects_extra.svg</property> + <property name="icon_size">6</property> + </object> + </child> + <child> + <object class="GtkLabel" id="label_desc_extra_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="label" translatable="yes"><b>E_xtra:</b> Provides more aesthetically pleasing set of effects. Requires faster graphics card.</property> + <property name="use_markup">True</property> + <property name="use_underline">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox_custom_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="no_show_all">True</property> + <child> + <object class="GtkRadioButton" id="custom_effects_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">no_effects_button</property> + <accelerator key="u" modifiers="" signal="activate"/> + <child> + <object class="GtkHBox" id="hbox_custom_effects_2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">6</property> + <child> + <object class="GtkImage" id="image_custom_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xpad">6</property> + <property name="pixbuf">/usr/share/gnome-control-center/pixmaps/visual-effects_custom.svg</property> + <property name="icon_size">6</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_desc_custom_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes"><b>C_ustom:</b> Uses custom set of effects.</property> + <property name="use_markup">True</property> + <property name="use_underline">True</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox_custom_effects"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkLabel" id="label_dummy_1"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <object class="GtkButton" id="custom_effects_edit_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="no">gtk-preferences</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_dummy_2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Visual Effects</property> + </object> + <packing> + <property name="position">4</property> + <property name="tab_fill">False</property> + </packing> + </child> </object> <packing> <property name="position">1</property> Index: gnome-control-center-2.30.0/capplets/appearance/Makefile.am =================================================================== --- gnome-control-center-2.30.0.orig/capplets/appearance/Makefile.am 2010-01-26 08:46:31.000000000 +0000 +++ gnome-control-center-2.30.0/capplets/appearance/Makefile.am 2010-04-10 00:19:11.640173172 +0100 @@ -9,6 +9,8 @@ appearance.h \ appearance-desktop.c \ appearance-desktop.h \ + appearance-effects.c\ + appearance-effects.h\ appearance-font.c \ appearance-font.h \ appearance-main.c \ Index: gnome-control-center-2.30.0/po/POTFILES.in =================================================================== --- gnome-control-center-2.30.0.orig/po/POTFILES.in 2009-08-24 11:54:41.000000000 +0100 +++ gnome-control-center-2.30.0/po/POTFILES.in 2010-04-10 00:19:11.640173172 +0100 @@ -16,6 +16,7 @@ capplets/accessibility/at-properties/at-properties.desktop.in.in capplets/accessibility/at-properties/main.c capplets/appearance/appearance-desktop.c +capplets/appearance/appearance-effects.c capplets/appearance/appearance-font.c capplets/appearance/appearance-main.c capplets/appearance/appearance-style.c