You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1749 lines
53 KiB

/* $Id$
*
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
* Copyright (c) 2006 Benedikt Meurer <benny@xfce.org>
*
* 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 Library 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 <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <libxfcegui4/libxfcegui4.h>
#include <libxfce4panel/xfce-itembar.h>
#include <libxfce4panel/xfce-panel-macros.h>
#include <libxfce4panel/xfce-panel-item-iface.h>
#include "frap-icon-entry.h"
#include "panel-properties.h"
#include "panel-private.h"
#include "panel-item-manager.h"
#include "panel-dnd.h"
#include "panel-dialogs.h"
#define BORDER 8
typedef struct _PanelItemsDialog PanelItemsDialog;
typedef struct _PanelManagerDialog PanelManagerDialog;
struct _PanelItemsDialog
{
GtkWidget *dlg;
GPtrArray *panels;
Panel *panel;
gint current;
GtkWidget *active;
GPtrArray *items;
GtkWidget *search_entry;
GtkWidget *tree;
GtkWidget *items_box;
gint panel_destroy_id;
};
struct _PanelManagerDialog
{
GtkWidget *dlg;
GPtrArray *panels;
Panel *panel;
gint current;
GtkTooltips *tips;
guint updating : 1;
/* add/remove/rename panel */
GtkWidget *panel_selector;
GtkWidget *add_panel;
GtkWidget *rm_panel;
/* appearance */
GtkWidget *size;
GtkWidget *transparency;
GtkWidget *activetrans;
#if 0
GtkWidget *position;
#endif
/* monitors */
GPtrArray *monitors;
/* position */
GtkWidget *fixed;
GtkWidget *floating;
GtkWidget *fixed_box;
GtkWidget *screen_position[12];
GtkWidget *fullwidth;
gint n_width_items;
GtkWidget *autohide;
GtkWidget *floating_box;
GtkWidget *orientation;
GtkWidget *handle_style;
};
static GtkWidget *panel_dialog_widget = NULL;
static GtkWidget *items_dialog_widget = NULL;
/*
* Common Code
* ===========
*/
static void
present_dialog (GtkWidget *dialog,
GPtrArray *panels)
{
gint n = panel_app_get_current_panel ();
GdkScreen *screen = gtk_widget_get_screen (g_ptr_array_index (panels, n));
if (screen != gtk_widget_get_screen (dialog))
gtk_window_set_screen (GTK_WINDOW (dialog), screen);
gtk_window_present (GTK_WINDOW (dialog));
}
/*
* Add Items Dialog
* ================
*/
static gboolean
item_configure_timeout (XfcePanelItem *item)
{
xfce_panel_item_configure (item);
return FALSE;
}
static XfcePanelItemInfo *
get_selected_tree_item (PanelItemsDialog *pid)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
XfcePanelItemInfo *info = NULL;
/* get the tree selection */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pid->tree));
if (G_LIKELY (selection))
{
/* get the selected item */
if (gtk_tree_selection_get_selected (selection, &model, &iter))
gtk_tree_model_get (model, &iter, 0, &info, -1);
}
return info;
}
static gboolean
add_selected_item (PanelItemsDialog *pid)
{
XfcePanelItemInfo *info;
GtkWidget *item = NULL;
/* get the selected item */
info = get_selected_tree_item (pid);
if (G_LIKELY (info && xfce_panel_item_manager_is_available (info->name)))
{
if (pid->active)
{
PanelPrivate *priv = PANEL_GET_PRIVATE (pid->panel);
gint n;
n = xfce_itembar_get_item_index (XFCE_ITEMBAR (priv->itembar), pid->active);
item = panel_insert_item (pid->panel, info->name, n + 1);
}
else
{
item = panel_add_item (pid->panel, info->name);
}
if (item)
g_idle_add ((GSourceFunc)item_configure_timeout, item);
else
xfce_err (_("Could not open \"%s\" module"), info->name);
return TRUE;
}
return FALSE;
}
static gboolean
treeview_dblclick (GtkWidget *tv,
GdkEventButton *evt,
PanelItemsDialog *pid)
{
if (evt->button == 1 && evt->type == GDK_2BUTTON_PRESS)
return add_selected_item (pid);
return FALSE;
}
static void
treeview_destroyed (GtkWidget *tv)
{
GtkTreeModel *store;
store = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (tv))));
gtk_list_store_clear (GTK_LIST_STORE (store));
}
static void
render_icon (GtkTreeViewColumn *col,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
XfcePanelItemInfo *info;
gtk_tree_model_get (model, iter, 0, &info, -1);
if (info)
{
g_object_set (G_OBJECT (cell),
"pixbuf", info->icon,
NULL);
}
else
{
g_object_set (G_OBJECT (cell),
"pixbuf", NULL,
NULL);
}
}
static void
render_text (GtkTreeViewColumn *col,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
GtkWidget *treeview)
{
XfcePanelItemInfo *info;
gboolean insensitive;
gchar text[512];
gtk_tree_model_get (model, iter, 0, &info, -1);
if (info)
{
insensitive = !xfce_panel_item_manager_is_available (info->name);
if (info->comment)
{
g_snprintf (text, sizeof(text), "<b>%s</b>\n%s", info->display_name,
info->comment);
}
else
{
g_snprintf (text, sizeof(text), "<b>%s</b>", info->display_name);
}
g_object_set (G_OBJECT (cell),
"markup", text,
"foreground-set", insensitive,
NULL);
}
else
{
g_object_set (G_OBJECT (cell),
"markup", "",
"foreground-set", TRUE,
NULL);
}
}
static void
treeview_data_received (GtkWidget *widget, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data,
guint info, guint time_, PanelItemsDialog *pid)
{
gboolean succeeded = FALSE;
GtkWidget *item;
/* get the drag source */
item = gtk_drag_get_source_widget (context);
if (item && XFCE_IS_PANEL_ITEM (item))
{
/* ask to remove the item */
xfce_panel_item_remove (XFCE_PANEL_ITEM (item));
succeeded = TRUE;
}
/* finish the drag */
gtk_drag_finish (context, succeeded, FALSE, time_);
}
static gboolean
treeview_drag_drop (GtkWidget *widget, GdkDragContext *context,
gint x, gint y, guint time_, PanelItemsDialog *pid)
{
GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
/* we cannot handle the drag data */
if (G_UNLIKELY (target == GDK_NONE))
return FALSE;
/* request the drag data */
gtk_drag_get_data (widget, context, target, time_);
/* we call gtk_drag_finish later */
return TRUE;
}
static void
treeview_drag_begin (GtkWidget *treeview, GdkDragContext *context,
PanelItemsDialog *pid)
{
XfcePanelItemInfo *item_info;
DBG (" + drag begin");
/* set nice drag icon */
item_info = get_selected_tree_item (pid);
if (G_LIKELY (item_info && item_info->icon))
gtk_drag_set_icon_pixbuf (context, item_info->icon, 0, 0);
}
static void
treeview_data_get (GtkWidget *widget, GdkDragContext *drag_context,
GtkSelectionData *data, guint info,
guint time_, PanelItemsDialog *pid)
{
XfcePanelItemInfo *item_info;
const gchar *item_name;
DBG (" + drag data get: %d", info);
if (G_LIKELY (info == TARGET_PLUGIN_NAME))
{
/* get the selected item info */
item_info = get_selected_tree_item (pid);
if (G_LIKELY (item_info))
{
item_name = item_info->name;
if (xfce_panel_item_manager_is_available (item_name))
{
DBG (" + set selection data: %s", item_name);
/* set the selection data */
gtk_selection_data_set (data, data->target, 8, (guchar *) item_name, strlen (item_name));
}
}
}
}
static gboolean
item_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer user_data)
{
XfcePanelItemInfo *info;
const gchar *text;
GtkWidget *entry = GTK_WIDGET (user_data);
gboolean visible;
gchar *text_casefolded;
gchar *info_casefolded;
gchar *normalized;
text = gtk_entry_get_text (GTK_ENTRY (entry));
if (G_UNLIKELY (*text == '\0'))
return TRUE;
gtk_tree_model_get (model, iter, 0, &info, -1);
if (G_UNLIKELY (info == NULL))
return TRUE;
normalized = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
text_casefolded = g_utf8_casefold (normalized, -1);
g_free (normalized);
normalized = g_utf8_normalize (info->display_name, -1, G_NORMALIZE_ALL);
info_casefolded = g_utf8_casefold (normalized, -1);
g_free (normalized);
visible = (strstr (info_casefolded, text_casefolded) != NULL);
g_free (info_casefolded);
if (!visible && info->comment)
{
normalized = g_utf8_normalize (info->comment, -1, G_NORMALIZE_ALL);
info_casefolded = g_utf8_casefold (normalized, -1);
g_free (normalized);
visible = (strstr (info_casefolded, text_casefolded) != NULL);
g_free (info_casefolded);
}
g_free (text_casefolded);
return visible;
}
static void
add_item_treeview (PanelItemsDialog *pid)
{
GtkWidget *tv, *scroll;
GtkCellRenderer *cell;
GtkTreeViewColumn *col;
GtkListStore *store;
GtkTreeModel *filter;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
guint i;
GdkColor *color;
GtkRequisition req;
scroll = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (scroll);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
GTK_POLICY_NEVER,
GTK_POLICY_NEVER);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (pid->items_box), scroll, TRUE, TRUE, 0);
store = gtk_list_store_new (1, G_TYPE_POINTER);
model = GTK_TREE_MODEL (store);
filter = gtk_tree_model_filter_new (model, NULL);
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
item_visible_func, pid->search_entry, NULL);
g_signal_connect_swapped (G_OBJECT (pid->search_entry), "changed",
G_CALLBACK (gtk_tree_model_filter_refilter), filter);
pid->tree = tv = gtk_tree_view_new_with_model (filter);
gtk_widget_show (tv);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tv), TRUE);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), FALSE);
gtk_container_add (GTK_CONTAINER (scroll), tv);
g_signal_connect (G_OBJECT (tv), "destroy",
G_CALLBACK (treeview_destroyed), NULL);
g_object_unref (G_OBJECT (filter));
g_object_unref (G_OBJECT (store));
/* dnd */
panel_dnd_set_source_name (tv);
panel_dnd_set_dest_name_and_widget (tv);
g_signal_connect (tv, "drag-data-get", G_CALLBACK (treeview_data_get), pid);
g_signal_connect (tv, "drag-data-received", G_CALLBACK (treeview_data_received), pid);
g_signal_connect (tv, "drag-drop", G_CALLBACK (treeview_drag_drop), pid);
g_signal_connect (tv, "drag-begin", G_CALLBACK (treeview_drag_begin), pid);
/* create the view */
col = gtk_tree_view_column_new ();
gtk_tree_view_column_set_spacing (col, BORDER);
gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col);
cell = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (col, cell, FALSE);
gtk_tree_view_column_set_cell_data_func (col, cell,
(GtkTreeCellDataFunc) render_icon,
NULL, NULL);
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (col, cell, TRUE);
gtk_tree_view_column_set_cell_data_func (col, cell,
(GtkTreeCellDataFunc) render_text,
tv, NULL);
color = &(tv->style->fg[GTK_STATE_INSENSITIVE]);
g_object_set (G_OBJECT (cell), "foreground-gdk", color, NULL);
/* fill model */
for (i = 0; i < pid->items->len; ++i)
{
if (i == 5)
{
gtk_widget_size_request (tv, &req);
gtk_widget_set_size_request (tv, -1, req.height);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
GTK_POLICY_NEVER,
GTK_POLICY_ALWAYS);
}
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0,
g_ptr_array_index (pid->items, i), -1);
}
g_signal_connect (G_OBJECT (tv), "button-press-event",
G_CALLBACK (treeview_dblclick), pid);
path = gtk_tree_path_new_from_string ("0");
gtk_tree_view_set_cursor (GTK_TREE_VIEW (tv), path, NULL, FALSE);
gtk_tree_path_free (path);
}
static void
item_dialog_opened (Panel *panel)
{
PanelPrivate *priv = PANEL_GET_PRIVATE (panel);
panel_block_autohide (panel);
xfce_itembar_raise_event_window (XFCE_ITEMBAR (priv->itembar));
panel_set_items_sensitive (panel, FALSE);
priv->edit_mode = TRUE;
}
static void
item_dialog_closed (Panel *panel)
{
PanelPrivate *priv = PANEL_GET_PRIVATE (panel);
panel_unblock_autohide (panel);
xfce_itembar_lower_event_window (XFCE_ITEMBAR (priv->itembar));
panel_set_items_sensitive (panel, TRUE);
priv->edit_mode = FALSE;
}
static void
item_dialog_response (GtkWidget *dlg,
gint response,
PanelItemsDialog *pid)
{
if (response != GTK_RESPONSE_HELP)
{
if (response == GTK_RESPONSE_OK)
{
add_selected_item (pid);
}
items_dialog_widget = NULL;
g_ptr_array_foreach (pid->panels, (GFunc)item_dialog_closed, NULL);
xfce_panel_item_manager_free_item_info_list (pid->items);
gtk_widget_destroy (dlg);
g_signal_handler_disconnect (pid->panel, pid->panel_destroy_id);
panel_slice_free (PanelItemsDialog, pid);
panel_app_save ();
}
else
{
xfce_exec_on_screen (gtk_widget_get_screen (dlg),
"xfhelp4 panel.html", FALSE, FALSE, NULL);
}
}
static void
items_dialog_panel_destroyed (PanelItemsDialog *pid)
{
gtk_dialog_response (GTK_DIALOG (pid->dlg), GTK_RESPONSE_CANCEL);
}
void
add_items_dialog (GPtrArray *panels,
GtkWidget *active_item)
{
PanelItemsDialog *pid;
Panel *panel;
GtkWidget *dlg, *vbox, *img, *hbox, *label;
gchar *markup;
if (items_dialog_widget)
{
present_dialog (items_dialog_widget, panels);
return;
}
pid = panel_slice_new0 (PanelItemsDialog);
/* panels */
pid->panels = panels;
pid->current = panel_app_get_current_panel();
panel = pid->panel = g_ptr_array_index (panels, pid->current);
pid->active = active_item;
/* available items */
pid->items = xfce_panel_item_manager_get_item_info_list ();
/* main dialog widget */
items_dialog_widget = pid->dlg = dlg =
xfce_titled_dialog_new_with_buttons (_("Add Items to the Panel"), NULL,
GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
GTK_STOCK_ADD, GTK_RESPONSE_OK,
NULL);
gtk_window_set_icon_name (GTK_WINDOW (dlg), "xfce4-panel");
g_signal_connect (G_OBJECT (dlg), "response",
G_CALLBACK (item_dialog_response), pid);
pid->panel_destroy_id =
g_signal_connect_swapped (G_OBJECT (panel), "destroy",
G_CALLBACK (items_dialog_panel_destroyed), pid);
pid->items_box = vbox = gtk_vbox_new (FALSE, BORDER);
gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER - 2);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0);
/* info */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
img = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO,
GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_misc_set_alignment (GTK_MISC (img), 0.0f, 0.5f);
gtk_widget_show (img);
gtk_box_pack_start (GTK_BOX (hbox), img, FALSE, FALSE, 0);
label = gtk_label_new (_("Drag items from the list to a panel or remove "
"them by dragging them back to the list."));
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
/* treeview */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0, 1.0f);
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
markup = g_strdup_printf ("<b>%s</b>", _("Available Items"));
gtk_label_set_markup (GTK_LABEL (label), markup);
g_free (markup);
/* the list filter entry (FIXME: Add tooltip? Jasper?) */
pid->search_entry = frap_icon_entry_new ();
frap_icon_entry_set_stock_id (FRAP_ICON_ENTRY (pid->search_entry), GTK_STOCK_FIND);
gtk_widget_show (pid->search_entry);
gtk_box_pack_end (GTK_BOX (hbox), pid->search_entry, FALSE, FALSE, 0);
add_item_treeview (pid);
/* make panels insensitive and set up dnd */
g_ptr_array_foreach (panels, (GFunc)item_dialog_opened, NULL);
gtk_window_stick(GTK_WINDOW (dlg));
xfce_gtk_window_center_on_monitor_with_pointer (GTK_WINDOW (dlg));
gtk_widget_show (dlg);
panel_app_register_dialog (dlg);
gtk_window_present (GTK_WINDOW (dlg));
}
/*
* Manage Panels Dialog
* ====================
*/
static gboolean
can_span_monitors (Panel *panel)
{
return ( (panel_app_monitors_equal_height () &&
panel_is_horizontal (panel))
|| (panel_app_monitors_equal_width () &&
!panel_is_horizontal (panel)) );
}
/* Update widgets */
static void
update_widgets (PanelManagerDialog *pmd)
{
PanelPrivate *priv = PANEL_GET_PRIVATE (pmd->panel);
guint i;
GtkToggleButton *tb;
XfceHandleStyle style;
pmd->updating = TRUE;
/* monitor */
if (pmd->monitors)
{
for (i = 0; i < pmd->monitors->len; ++i)
{
tb = g_ptr_array_index (pmd->monitors, i);
gtk_toggle_button_set_active (tb, i == (guint) priv->monitor);
}
}
/* appearance */
gtk_range_set_value (GTK_RANGE (pmd->size), priv->size);
if (pmd->transparency)
{
gtk_range_set_value (GTK_RANGE (pmd->transparency),
priv->transparency);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pmd->activetrans),
!priv->activetrans);
}
/* behavior */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pmd->autohide),
priv->autohide);
/* position */
if (!xfce_screen_position_is_floating (priv->screen_position))
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pmd->fixed), TRUE);
gtk_widget_hide (pmd->floating_box);
gtk_widget_show (pmd->fixed_box);
for (i = 0; i < 12; ++i)
{
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (pmd->screen_position[i]),
priv->screen_position == i + 1);
}
gtk_combo_box_set_active (GTK_COMBO_BOX (pmd->fullwidth),
priv->full_width);
}
else
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pmd->floating), TRUE);
gtk_widget_hide (pmd->fixed_box);
gtk_widget_show (pmd->floating_box);
gtk_combo_box_set_active (GTK_COMBO_BOX (pmd->orientation),
panel_is_horizontal (pmd->panel) ? 0 : 1);
style = xfce_panel_window_get_handle_style (
XFCE_PANEL_WINDOW (pmd->panel));
if (style == XFCE_HANDLE_STYLE_NONE)
style = XFCE_HANDLE_STYLE_BOTH;
gtk_combo_box_set_active (GTK_COMBO_BOX (pmd->handle_style),
style - 1);
}
pmd->updating = FALSE;
}
/* position */
static void
type_changed (GtkToggleButton *tb,
PanelManagerDialog *pmd)
{
PanelPrivate *priv;