/* vim: set expandtab ts=4 sw=4: */ /* * Copyright (c) 2003 Andre Lerche * Copyright (c) 2003 Benedikt Meurer * Copyright (c) 2006 Jani Monoses * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include typedef struct { XfcePanelPlugin *plugin; GtkWidget *windowlist; NetkScreen *screen; int ScreenCallbackId; //FIXME is this needed? gboolean all_workspaces; GtkTooltips *tooltips; } Windowlist; /* Panel Plugin Interface */ static void windowlist_construct (XfcePanelPlugin * plugin); XFCE_PANEL_PLUGIN_REGISTER_INTERNAL (windowlist_construct); /* internal functions */ static void plugin_activate_workspace (GtkWidget *widget, gpointer data) { NetkWorkspace *ws = data; netk_workspace_activate (ws); } static void plugin_activate_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; NetkScreen *screen; NetkWorkspace *ws; screen = netk_screen_get_default (); ws = netk_window_get_workspace (win); if (ws != netk_screen_get_active_workspace (screen)) { netk_workspace_activate (ws); } netk_window_activate (win); } static void plugin_stick_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_stick (win); } static void plugin_unstick_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_unstick (win); } static void plugin_minimize_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_minimize (win); } static void plugin_unminimize_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_unminimize (win); } static void plugin_maximize_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_maximize (win); } static void plugin_unmaximize_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_unmaximize (win); } static void plugin_shade_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_shade (win); } static void plugin_unshade_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_unshade (win); } static void plugin_close_window (GtkWidget *widget, gpointer data) { NetkWindow *win = data; netk_window_close (win); } static GtkWidget * plugin_create_action_menu (NetkWindow *win) { GtkWidget *menu = NULL; GtkWidget *item, *image; const char *wname = NULL; GString *label; wname = netk_window_get_name (win); label = g_string_new (wname); if (label->len >= 20) { g_string_truncate (label, 20); g_string_append (label, " ..."); } menu = gtk_menu_new (); item = gtk_menu_item_new_with_label (label->str); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); gtk_widget_set_sensitive (item, FALSE); g_signal_connect (item, "activate", G_CALLBACK(plugin_activate_window), win); g_string_free (label, TRUE); item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); if (netk_window_is_maximized(win)) { item = gtk_image_menu_item_new_with_label ("Unmaximize"); image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_unmaximize_window), win); } else { item = gtk_image_menu_item_new_with_label ("Maximize"); image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_maximize_window), win); } if (netk_window_is_minimized(win)) { item = gtk_image_menu_item_new_with_label ("Show"); image = gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_unminimize_window), win); } else { item = gtk_image_menu_item_new_with_label ("Hide"); image = gtk_image_new_from_stock (GTK_STOCK_UNDO, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_minimize_window), win); } if (netk_window_is_shaded(win)) { item = gtk_image_menu_item_new_with_label ("Unshade"); image = gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_unshade_window), win); } else { item = gtk_image_menu_item_new_with_label ("Shade"); image = gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_shade_window), win); } if (netk_window_is_sticky(win)) { item = gtk_image_menu_item_new_with_label ("Unstick"); image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_unstick_window), win); } else { item = gtk_image_menu_item_new_with_label ("Stick"); image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_stick_window), win); } item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); item = gtk_image_menu_item_new_with_label ("Close"); image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (item, "activate", G_CALLBACK(plugin_close_window), win); return (menu); } static void popup_action_menu (GtkWidget *widget, gpointer data) { NetkWindow *win = data; static GtkWidget *menu = NULL; if (menu) { gtk_widget_destroy(menu); } menu = plugin_create_action_menu (win); gtk_widget_show_all (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); } static void menu_item_clicked (GtkWidget *item, GdkEventButton *ev, gpointer data) { NetkWindow *win = data; if (ev->button == 1) { plugin_activate_window (NULL, win); } else if (ev->button == 3) { popup_action_menu (item, win); } gtk_menu_popdown (GTK_MENU(gtk_widget_get_parent(item))); } static void set_num_screens (gpointer num) { netk_screen_change_workspace_count (netk_screen_get_default(), GPOINTER_TO_INT(num)); } // the following two functions are based on xfdesktop code static GtkWidget * create_menu_item (NetkWindow *win, GList **unref_needed, Windowlist *wl) { const char *wname = NULL; GtkWidget *item; GString *label; GdkPixbuf *icon = NULL, *tmp; if (netk_window_is_skip_pager (win) || netk_window_is_skip_tasklist (win)) return NULL; wname = netk_window_get_name (win); label = g_string_new (wname); if (label->len >= 20) { g_string_truncate (label, 20); g_string_append (label, " ..."); } if (netk_window_is_minimized (win)) { g_string_prepend (label, "["); g_string_append (label, "]"); } tmp = netk_window_get_icon(win); if (tmp) { gint w, h; w = gdk_pixbuf_get_width(tmp); h = gdk_pixbuf_get_height(tmp); if (w != 22 || h != 22) { icon = gdk_pixbuf_scale_simple(tmp, 24, 24, GDK_INTERP_BILINEAR); *unref_needed = g_list_prepend(*unref_needed, icon); } else { icon = tmp; } } if (icon) { GtkWidget *img = gtk_image_new_from_pixbuf(icon); gtk_widget_show(img); item = gtk_image_menu_item_new_with_label(label->str); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); } else { item = gtk_menu_item_new_with_label (label->str); } gtk_tooltips_set_tip (wl->tooltips, item, wname, NULL); g_string_free (label, TRUE); return item; } static void plugin_windowlist_clicked (GtkWidget *w, Windowlist *wl) { static GtkWidget *menu = NULL; GtkWidget *item, *label; NetkWindow *win; NetkWorkspace *ws, *aws, *winws; NetkScreen *s; int wscount, i; GList *windows, *li, *l, *unref_needed=NULL; GtkStyle *style; if (menu) { gtk_widget_destroy(menu); } s = netk_screen_get_default(); windows = netk_screen_get_windows_stacked(s); aws = netk_screen_get_active_workspace (s); menu = gtk_menu_new (); style = gtk_widget_get_style (menu); item = gtk_menu_item_new_with_label N_("Window list"); gtk_widget_set_sensitive (item, FALSE); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); if (wl->all_workspaces) { wscount = netk_screen_get_workspace_count(s); } else { wscount = 1; } for (i = 0; iall_workspaces) { ws = netk_screen_get_workspace(s, i); } else { ws = netk_screen_get_active_workspace (s); } realname = netk_workspace_get_name (ws); if (realname) { ws_name = g_strdup_printf ("%s", realname); } else { ws_name = g_strdup_printf ("%d", i + 1); } item = gtk_menu_item_new_with_label (ws_name); g_signal_connect (item, "activate", G_CALLBACK(plugin_activate_workspace), ws); g_free (ws_name); label = gtk_bin_get_child (GTK_BIN (item)); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); if (ws == aws) { gtk_widget_set_sensitive (item, FALSE); } item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); for (li = windows; li; li = li->next ) { win = li->data; winws = netk_window_get_workspace (win); if (ws != winws && !(netk_window_is_sticky(win) && ws == aws)) { continue; } item = create_menu_item (win, &unref_needed, wl); if (!item) continue; if (ws != aws) { gtk_widget_modify_fg (gtk_bin_get_child (GTK_BIN (item)), GTK_STATE_NORMAL, &(style->fg[GTK_STATE_INSENSITIVE])); } g_signal_connect (item, "button-release-event", G_CALLBACK(menu_item_clicked), win); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); } item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); } wscount = netk_screen_get_workspace_count (s); item = gtk_menu_item_new_with_label (_("Add workspace")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect_swapped (item, "activate", G_CALLBACK (set_num_screens), GINT_TO_POINTER (wscount + 1)); item = gtk_menu_item_new_with_label (_("Delete workspace")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect_swapped (item, "activate", G_CALLBACK (set_num_screens), GINT_TO_POINTER (wscount - 1)); gtk_widget_show_all (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); if (unref_needed) { for(l=unref_needed; l; l=l->next) { g_object_unref(G_OBJECT(l->data)); } g_list_free(unref_needed); unref_needed = NULL; } } static void plugin_active_window_changed (GtkWidget *w, Windowlist *wl) { NetkWindow *win; GdkPixbuf *pb; if (win = netk_screen_get_active_window(wl->screen)) { pb = netk_window_get_icon (win); if (pb) { xfce_iconbutton_set_pixbuf(XFCE_ICONBUTTON(wl->windowlist), pb); gtk_tooltips_set_tip (wl->tooltips, wl->windowlist, netk_window_get_name (win), NULL); } } } /* Configuration */ static void windowlist_read_rc_file (XfcePanelPlugin *plugin, Windowlist *wl) { char *file; XfceRc *rc; int all_workspaces; all_workspaces = 0; if ((file = xfce_panel_plugin_lookup_rc_file (plugin)) != NULL) { rc = xfce_rc_simple_open (file, TRUE); g_free (file); if (rc != NULL) { all_workspaces = xfce_rc_read_int_entry (rc, "all_workspaces", all_workspaces); xfce_rc_close (rc); } } wl->all_workspaces = (all_workspaces == 1); } static void windowlist_write_rc_file (XfcePanelPlugin *plugin, Windowlist *wl) { char *file; XfceRc *rc; if (!(file = xfce_panel_plugin_save_location (plugin, TRUE))) return; rc = xfce_rc_simple_open (file, FALSE); g_free (file); if (!rc) return; xfce_rc_write_int_entry (rc, "all_workspaces", wl->all_workspaces); xfce_rc_close (rc); } static void plugin_cb_changed (GtkToggleButton *cb, Windowlist *wl) { wl->all_workspaces = gtk_toggle_button_get_active (cb); } static void windowlist_dialog_response (GtkWidget *dlg, int reponse, Windowlist *wl) { g_object_set_data (G_OBJECT (wl->plugin), "dialog", NULL); gtk_widget_destroy (dlg); xfce_panel_plugin_unblock_menu (wl->plugin); windowlist_write_rc_file (wl->plugin, wl); } static void windowlist_properties_dialog (XfcePanelPlugin *plugin, Windowlist *wl) { GtkWidget *dlg, *header, *mainvbox, *frame, *cb; xfce_panel_plugin_block_menu (plugin); dlg = gtk_dialog_new_with_buttons (_("Properties"), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (plugin))), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL); g_object_set_data (G_OBJECT (plugin), "dialog", dlg); gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER); g_signal_connect (dlg, "response", G_CALLBACK (windowlist_dialog_response), wl); gtk_container_set_border_width (GTK_CONTAINER (dlg), 2); header = xfce_create_header (NULL, _("Window List")); gtk_widget_set_size_request (GTK_BIN (header)->child, 200, 32); gtk_container_set_border_width (GTK_CONTAINER (header), 6); gtk_widget_show (header); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), header, FALSE, TRUE, 0); mainvbox = gtk_vbox_new (FALSE, 8); gtk_container_set_border_width (GTK_CONTAINER (mainvbox), 5); gtk_widget_show (mainvbox); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), mainvbox, TRUE, TRUE, 0); frame = gtk_frame_new (NULL); cb = gtk_check_button_new_with_label ("Include all Workspaces"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb), wl->all_workspaces); g_signal_connect (cb, "toggled", G_CALLBACK (plugin_cb_changed), wl); gtk_container_add (GTK_CONTAINER(frame), cb); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, FALSE, FALSE, 0); gtk_widget_show_all (frame); gtk_widget_show (dlg); } /* Handle free-data signal */ static void windowlist_free_data (XfcePanelPlugin * plugin, Windowlist *wl) { g_signal_handler_disconnect (wl->screen, wl->ScreenCallbackId); } static gboolean windowlist_set_size (XfcePanelPlugin * plugin, int size, Windowlist * wl) { gtk_widget_set_size_request (GTK_WIDGET (wl->windowlist), size, size); return TRUE; } static Windowlist * windowlist_new (XfcePanelPlugin * plugin) { int size; GdkPixbuf * pb; GtkWidget * dummy; Windowlist *wl = g_new0 (Windowlist, 1); wl->plugin = plugin; wl->tooltips = gtk_tooltips_new (); wl->all_workspaces = FALSE; wl->screen=netk_screen_get_default(); netk_screen_force_update (wl->screen); dummy = gtk_invisible_new(); pb = gtk_widget_render_icon (dummy, GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU, NULL); wl->windowlist = xfce_iconbutton_new_from_pixbuf(pb); g_object_unref (pb); size = xfce_panel_plugin_get_size (plugin); gtk_widget_set_size_request (GTK_WIDGET (wl->windowlist), size, size); gtk_button_set_relief (GTK_BUTTON (wl->windowlist), GTK_RELIEF_NONE); xfce_panel_plugin_add_action_widget (plugin, wl->windowlist); g_signal_connect(wl->windowlist, "clicked", G_CALLBACK(plugin_windowlist_clicked), wl); wl->ScreenCallbackId = g_signal_connect(wl->screen, "active-window-changed", G_CALLBACK(plugin_active_window_changed), wl); gtk_widget_show(wl->windowlist); gtk_container_add (GTK_CONTAINER(plugin), wl->windowlist); return wl; } static void windowlist_construct (XfcePanelPlugin * plugin) { Windowlist * wl = windowlist_new (plugin); g_signal_connect (plugin, "free-data", G_CALLBACK (windowlist_free_data), wl); g_signal_connect (plugin, "save", G_CALLBACK (windowlist_write_rc_file), wl); g_signal_connect (plugin, "size-changed", G_CALLBACK (windowlist_set_size), wl); xfce_panel_plugin_menu_show_configure (plugin); g_signal_connect (plugin, "configure-plugin", G_CALLBACK (windowlist_properties_dialog), wl); windowlist_read_rc_file(plugin, wl); }