summaryrefslogtreecommitdiff
path: root/applets/wncklet/showdesktop.c
diff options
context:
space:
mode:
Diffstat (limited to 'applets/wncklet/showdesktop.c')
-rw-r--r--applets/wncklet/showdesktop.c533
1 files changed, 533 insertions, 0 deletions
diff --git a/applets/wncklet/showdesktop.c b/applets/wncklet/showdesktop.c
new file mode 100644
index 00000000..7cfcb88d
--- /dev/null
+++ b/applets/wncklet/showdesktop.c
@@ -0,0 +1,533 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* "Show desktop" panel applet */
+
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ * Developed by Havoc Pennington
+ *
+ * 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 WNCK_I_KNOW_THIS_IS_UNSTABLE 1
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <libwnck/screen.h>
+
+#include "wncklet.h"
+#include "showdesktop.h"
+
+#include <string.h>
+
+#define TIMEOUT_ACTIVATE_SECONDS 1
+#define SHOW_DESKTOP_ICON "user-desktop"
+
+
+typedef struct {
+ /* widgets */
+ GtkWidget* applet;
+ GtkWidget* button;
+ GtkWidget* image;
+
+ GtkOrientation orient;
+ int size;
+
+ WnckScreen* wnck_screen;
+
+ guint showing_desktop: 1;
+ guint button_activate;
+
+ GtkIconTheme* icon_theme;
+} ShowDesktopData;
+
+static void display_help_dialog(GtkAction* action, ShowDesktopData* sdd);
+static void display_about_dialog(GtkAction* action, ShowDesktopData* sdd);
+
+static void update_icon(ShowDesktopData* sdd);
+static void update_button_state(ShowDesktopData* sdd);
+static void update_button_display(ShowDesktopData* sdd);
+
+static void theme_changed_callback(GtkIconTheme* icon_theme, ShowDesktopData* sdd);
+
+static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd);
+static void show_desktop_changed_callback(WnckScreen* screen, ShowDesktopData* sdd);
+
+/* this is when the panel orientation changes */
+
+static void applet_change_orient(MatePanelApplet* applet, MatePanelAppletOrient orient, ShowDesktopData* sdd)
+{
+ GtkOrientation new_orient;
+
+ switch (orient)
+ {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ new_orient = GTK_ORIENTATION_VERTICAL;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ default:
+ new_orient = GTK_ORIENTATION_HORIZONTAL;
+ break;
+ }
+
+ if (new_orient == sdd->orient)
+ return;
+
+ sdd->orient = new_orient;
+
+ update_icon (sdd);
+}
+
+/* this is when the panel size changes */
+static void button_size_allocated(GtkWidget* button, GtkAllocation* allocation, ShowDesktopData* sdd)
+{
+ /*
+ if ((sdd->orient == GTK_ORIENTATION_HORIZONTAL) && (sdd->size == allocation->height))
+ {
+ return;
+ }
+ else if ((sdd->orient == GTK_ORIENTATION_VERTICAL) && (sdd->size == allocation->width))
+ {
+ return;
+ }
+ */
+
+ if (((sdd->orient == GTK_ORIENTATION_HORIZONTAL) && (sdd->size == allocation->height)) || ((sdd->orient == GTK_ORIENTATION_VERTICAL) && (sdd->size == allocation->width)))
+ return;
+
+ switch (sdd->orient)
+ {
+ case GTK_ORIENTATION_HORIZONTAL:
+ sdd->size = allocation->height;
+ break;
+ case GTK_ORIENTATION_VERTICAL:
+ sdd->size = allocation->width;
+ break;
+ }
+
+ update_icon(sdd);
+}
+
+static void update_icon(ShowDesktopData* sdd)
+{
+ GtkStyle* style;
+ int width, height;
+ GdkPixbuf* icon;
+ GdkPixbuf* scaled;
+ int icon_size;
+ GError* error;
+ int focus_width = 0;
+ int focus_pad = 0;
+ int thickness = 0;
+
+ if (!sdd->icon_theme)
+ return;
+
+ gtk_widget_style_get (sdd->button, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL);
+
+ style = gtk_widget_get_style(sdd->button);
+
+ switch (sdd->orient)
+ {
+ case GTK_ORIENTATION_HORIZONTAL:
+ thickness = style->ythickness;
+ break;
+ case GTK_ORIENTATION_VERTICAL:
+ thickness = style->xthickness;
+ break;
+ }
+
+ icon_size = sdd->size - 2 * (focus_width + focus_pad + thickness);
+
+ if (icon_size < 22)
+ icon_size = 16;
+ else if (icon_size < 32)
+ icon_size = 22;
+ else if (icon_size < 48)
+ icon_size = 32;
+
+ error = NULL;
+ icon = gtk_icon_theme_load_icon (sdd->icon_theme, SHOW_DESKTOP_ICON, icon_size, 0, &error);
+
+ if (icon == NULL)
+ {
+ g_printerr(_("Failed to load %s: %s\n"), SHOW_DESKTOP_ICON, error ? error->message : _("Icon not found"));
+
+ if (error)
+ {
+ g_error_free(error);
+ error = NULL;
+ }
+
+ gtk_image_set_from_stock(GTK_IMAGE (sdd->image), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ return;
+ }
+
+ width = gdk_pixbuf_get_width(icon);
+ height = gdk_pixbuf_get_height(icon);
+
+ scaled = NULL;
+
+ /* Make it fit on the given panel */
+ switch (sdd->orient)
+ {
+ case GTK_ORIENTATION_HORIZONTAL:
+ width = (icon_size * width) / height;
+ height = icon_size;
+ break;
+ case GTK_ORIENTATION_VERTICAL:
+ height = (icon_size * height) / width;
+ width = icon_size;
+ break;
+ }
+
+ scaled = gdk_pixbuf_scale_simple(icon, width, height, GDK_INTERP_BILINEAR);
+
+ if (scaled != NULL)
+ {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(sdd->image), scaled);
+ g_object_unref(scaled);
+ }
+ else
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (sdd->image), icon);
+ }
+
+ g_object_unref (icon);
+}
+
+static const GtkActionEntry show_desktop_menu_actions[] = {
+ {
+ "ShowDesktopHelp",
+ GTK_STOCK_HELP,
+ N_("_Help"),
+ NULL,
+ NULL,
+ G_CALLBACK(display_help_dialog)
+ },
+ {
+ "ShowDesktopAbout",
+ GTK_STOCK_ABOUT,
+ N_("_About"),
+ NULL,
+ NULL,
+ G_CALLBACK(display_about_dialog)
+ }
+};
+
+/* This updates things that should be consistent with the button's appearance,
+ * and update_button_state updates the button appearance itself
+ */
+static void update_button_display(ShowDesktopData* sdd)
+{
+ const char* tip;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdd->button)))
+ {
+ tip = _("Click here to restore hidden windows.");
+ }
+ else
+ {
+ tip = _("Click here to hide all windows and show the desktop.");
+ }
+
+ gtk_widget_set_tooltip_text(sdd->button, tip);
+}
+
+static void update_button_state(ShowDesktopData* sdd)
+{
+ if (sdd->showing_desktop)
+ {
+ g_signal_handlers_block_by_func(G_OBJECT(sdd->button), G_CALLBACK(button_toggled_callback), sdd);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdd->button), TRUE);
+ g_signal_handlers_unblock_by_func(G_OBJECT(sdd->button), G_CALLBACK(button_toggled_callback), sdd);
+ }
+ else
+ {
+ g_signal_handlers_block_by_func(G_OBJECT(sdd->button), G_CALLBACK(button_toggled_callback), sdd);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdd->button), FALSE);
+ g_signal_handlers_unblock_by_func(G_OBJECT(sdd->button), G_CALLBACK(button_toggled_callback), sdd);
+ }
+
+ update_button_display (sdd);
+}
+
+static void applet_destroyed(GtkWidget* applet, ShowDesktopData* sdd)
+{
+ if (sdd->button_activate != 0)
+ {
+ g_source_remove(sdd->button_activate);
+ sdd->button_activate = 0;
+ }
+
+ if (sdd->wnck_screen != NULL)
+ {
+ g_signal_handlers_disconnect_by_func(sdd->wnck_screen, show_desktop_changed_callback, sdd);
+ sdd->wnck_screen = NULL;
+ }
+
+ if (sdd->icon_theme != NULL)
+ {
+ g_signal_handlers_disconnect_by_func(sdd->icon_theme, theme_changed_callback, sdd);
+ sdd->icon_theme = NULL;
+ }
+
+ g_free (sdd);
+}
+
+static gboolean do_not_eat_button_press(GtkWidget* widget, GdkEventButton* event)
+{
+ if (event->button != 1)
+ {
+ g_signal_stop_emission_by_name(widget, "button_press_event");
+ }
+
+ return FALSE;
+}
+
+static gboolean button_motion_timeout(gpointer data)
+{
+ ShowDesktopData* sdd = (ShowDesktopData*) data;
+
+ sdd->button_activate = 0;
+
+ g_signal_emit_by_name(G_OBJECT(sdd->button), "clicked", sdd);
+
+ return FALSE;
+}
+
+static void button_drag_leave(GtkWidget* widget, GdkDragContext* context, guint time, ShowDesktopData* sdd)
+{
+ if (sdd->button_activate != 0)
+ {
+ g_source_remove(sdd->button_activate);
+ sdd->button_activate = 0;
+ }
+}
+
+static gboolean button_drag_motion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time, ShowDesktopData* sdd)
+{
+ if (sdd->button_activate == 0)
+ sdd->button_activate = g_timeout_add_seconds (TIMEOUT_ACTIVATE_SECONDS, button_motion_timeout, sdd);
+
+ gdk_drag_status(context, 0, time);
+
+ return TRUE;
+}
+
+static void show_desktop_applet_realized(MatePanelApplet* applet, gpointer data)
+{
+ ShowDesktopData* sdd;
+ GdkScreen* screen;
+
+ sdd = (ShowDesktopData*) data;
+
+ if (sdd->wnck_screen != NULL)
+ g_signal_handlers_disconnect_by_func(sdd->wnck_screen, show_desktop_changed_callback, sdd);
+
+ if (sdd->icon_theme != NULL)
+ g_signal_handlers_disconnect_by_func(sdd->icon_theme, theme_changed_callback, sdd);
+
+ screen = gtk_widget_get_screen(sdd->applet);
+ sdd->wnck_screen = wnck_screen_get(gdk_screen_get_number (screen));
+
+ if (sdd->wnck_screen != NULL)
+ wncklet_connect_while_alive(sdd->wnck_screen, "showing_desktop_changed", G_CALLBACK(show_desktop_changed_callback), sdd, sdd->applet);
+ else
+ g_warning("Could not get WnckScreen!");
+
+ show_desktop_changed_callback(sdd->wnck_screen, sdd);
+
+ sdd->icon_theme = gtk_icon_theme_get_for_screen (screen);
+ wncklet_connect_while_alive(sdd->icon_theme, "changed", G_CALLBACK(theme_changed_callback), sdd, sdd->applet);
+
+ update_icon (sdd);
+}
+
+static void theme_changed_callback(GtkIconTheme* icon_theme, ShowDesktopData* sdd)
+{
+ update_icon (sdd);
+}
+
+gboolean show_desktop_applet_fill(MatePanelApplet* applet)
+{
+ ShowDesktopData* sdd;
+ GtkActionGroup* action_group;
+ gchar* ui_path;
+ AtkObject* atk_obj;
+
+ mate_panel_applet_set_flags(applet, MATE_PANEL_APPLET_EXPAND_MINOR);
+
+ sdd = g_new0(ShowDesktopData, 1);
+
+ sdd->applet = GTK_WIDGET(applet);
+
+ sdd->image = gtk_image_new();
+
+ switch (mate_panel_applet_get_orient(applet))
+ {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ sdd->orient = GTK_ORIENTATION_VERTICAL;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ default:
+ sdd->orient = GTK_ORIENTATION_HORIZONTAL;
+ break;
+ }
+
+ sdd->size = mate_panel_applet_get_size(MATE_PANEL_APPLET(sdd->applet));
+
+ g_signal_connect(G_OBJECT(sdd->applet), "realize", G_CALLBACK(show_desktop_applet_realized), sdd);
+
+ sdd->button = gtk_toggle_button_new ();
+
+ gtk_widget_set_name (sdd->button, "showdesktop-button");
+ gtk_rc_parse_string ("\n"
+ " style \"showdesktop-button-style\"\n"
+ " {\n"
+ " GtkWidget::focus-line-width=0\n"
+ " GtkWidget::focus-padding=0\n"
+ " }\n"
+ "\n"
+ " widget \"*.showdesktop-button\" style \"showdesktop-button-style\"\n"
+ "\n");
+
+ atk_obj = gtk_widget_get_accessible(sdd->button);
+ atk_object_set_name (atk_obj, _("Show Desktop Button"));
+ g_signal_connect(G_OBJECT(sdd->button), "button_press_event", G_CALLBACK(do_not_eat_button_press), NULL);
+
+ g_signal_connect(G_OBJECT(sdd->button), "toggled", G_CALLBACK(button_toggled_callback), sdd);
+
+ gtk_container_set_border_width(GTK_CONTAINER(sdd->button), 0);
+ gtk_container_add(GTK_CONTAINER(sdd->button), sdd->image);
+ gtk_container_add(GTK_CONTAINER(sdd->applet), sdd->button);
+
+ g_signal_connect (G_OBJECT(sdd->button), "size_allocate", G_CALLBACK(button_size_allocated), sdd);
+
+ /* FIXME: Update this comment. */
+ /* we have to bind change_orient before we do applet_widget_add
+ since we need to get an initial change_orient signal to set our
+ initial oriantation, and we get that during the _add call */
+ g_signal_connect(G_OBJECT (sdd->applet), "change_orient", G_CALLBACK (applet_change_orient), sdd);
+
+ mate_panel_applet_set_background_widget(MATE_PANEL_APPLET (sdd->applet), GTK_WIDGET(sdd->applet));
+
+ action_group = gtk_action_group_new("ShowDesktop Applet Actions");
+ gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions(action_group, show_desktop_menu_actions, G_N_ELEMENTS (show_desktop_menu_actions), sdd);
+ ui_path = g_build_filename(WNCK_MENU_UI_DIR, "showdesktop-menu.xml", NULL);
+ mate_panel_applet_setup_menu_from_file(MATE_PANEL_APPLET(sdd->applet), ui_path, action_group);
+ g_free(ui_path);
+ g_object_unref(action_group);
+
+ g_signal_connect(G_OBJECT(sdd->applet), "destroy", G_CALLBACK(applet_destroyed), sdd);
+
+ gtk_drag_dest_set(GTK_WIDGET(sdd->button), 0, NULL, 0, 0);
+
+ g_signal_connect(G_OBJECT(sdd->button), "drag_motion", G_CALLBACK (button_drag_motion), sdd);
+ g_signal_connect(G_OBJECT(sdd->button), "drag_leave", G_CALLBACK (button_drag_leave), sdd);
+
+ gtk_widget_show_all(sdd->applet);
+
+ return TRUE;
+}
+
+static void display_help_dialog(GtkAction* action, ShowDesktopData* sdd)
+{
+ wncklet_display_help(sdd->applet, "user-guide", "gospanel-564", SHOW_DESKTOP_ICON);
+}
+
+static void display_about_dialog(GtkAction* action, ShowDesktopData* sdd)
+{
+ static const gchar* authors[] = {
+ "Havoc Pennington <[email protected]>",
+ NULL
+ };
+ static const char* documenters[] = {
+ "Sun MATE Documentation Team <[email protected]>",
+ NULL
+ };
+
+ /* Translator credits */
+ //const char* translator_credits = _("translator-credits");
+ char copyright[] = \
+ "Copyright \xc2\xa9 2002 Red Hat, Inc.";
+
+ gtk_show_about_dialog(GTK_WINDOW(sdd->applet),
+ "program-name", _("Show Desktop Button"),
+ "authors", authors,
+ "comments", _("This button lets you hide all windows and show the desktop."),
+ "copyright", copyright,
+ "documenters", documenters,
+ "icon-name", SHOW_DESKTOP_ICON,
+ "logo-icon-name", SHOW_DESKTOP_ICON,
+ "translator-credits", _("translator-credits"),
+ "version", VERSION,
+ "website", "http://matsusoft.com.ar/projects/mate/",
+ NULL);
+}
+
+static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd)
+{
+ if (!gdk_x11_screen_supports_net_wm_hint(gtk_widget_get_screen(button), gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE)))
+ {
+ static GtkWidget* dialog = NULL;
+
+ if (dialog && gtk_widget_get_screen(dialog) != gtk_widget_get_screen(button))
+ gtk_widget_destroy (dialog);
+
+ if (dialog)
+ {
+ gtk_window_present(GTK_WINDOW(dialog));
+ return;
+ }
+
+ dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Your window manager does not support the show desktop button, or you are not running a window manager."));
+
+ g_object_add_weak_pointer(G_OBJECT(dialog), (gpointer) &dialog);
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
+
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+ gtk_window_set_screen(GTK_WINDOW(dialog), gtk_widget_get_screen(button));
+ gtk_widget_show(dialog);
+
+ return;
+ }
+
+ if (sdd->wnck_screen != NULL)
+ wnck_screen_toggle_showing_desktop(sdd->wnck_screen, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
+
+ update_button_display (sdd);
+}
+
+static void show_desktop_changed_callback(WnckScreen* screen, ShowDesktopData* sdd)
+{
+ if (sdd->wnck_screen != NULL)
+ sdd->showing_desktop = wnck_screen_get_showing_desktop(sdd->wnck_screen);
+
+ update_button_state (sdd);
+}