/* xfce4-places-plugin
*
* This file handles the GUI. It "owns" the model and cfg.
*
* Copyright (c) 2007 Diego Ongaro <ongardie@gmail.com>
*
* Largely based on:
*
* - notes plugin
* panel-plugin.c - (xfce4-panel plugin for temporary notes)
* Copyright (c) 2006 Mike Massonnet <mmassonnet@gmail.com>
*
* - xfdesktop menu plugin
* desktop-menu-plugin.c - xfce4-panel plugin that displays the desktop menu
* Copyright (C) 2004 Brian Tarricone, <bjt23@cornell.edu>
*
* - launcher plugin
* launcher.c - (xfce4-panel plugin that opens programs)
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
* Copyright (c) 2006-2007 Nick Schermer <nick@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
#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>
#include <libxfce4panel/xfce-panel-plugin.h>
#include <libxfce4panel/xfce-panel-convenience.h>
#include <libxfce4panel/xfce-hvbox.h>
#include <libxfcegui4/libxfcegui4.h>
#include <string.h>
#include "view.h"
#include "support.h"
#include "cfg.h"
#include "model.h"
#include "model_system.h"
#include "model_volumes.h"
#include "model_user.h"
struct _PlacesView
{
/* plugin */
XfcePanelPlugin *plugin;
/* configuration */
PlacesCfg *cfg;
PlacesCfgViewIface *cfg_iface;
PlacesViewCfgIface *view_cfg_iface;
/* view */
GtkWidget *button;
GtkWidget *button_image;
GtkWidget *button_label;
GtkWidget *menu;
GtkTooltips *tooltips;
gboolean needs_separator;
guint menu_timeout_id;
GtkOrientation orientation;
gint size;
gboolean show_button_icon;
gboolean show_button_label;
gchar *label_tooltip_text;
gboolean force_update_theme;
/* model */
GList *bookmark_groups;
};
/* Debugging */
#if defined(DEBUG) && (DEBUG > 0)
static guint places_debug_menu_timeout_count = 0;
#define PLACES_DEBUG_MENU_TIMEOUT_COUNT(delta) \
G_STMT_START{ \
places_debug_menu_timeout_count += delta; \
DBG("Menu timeout count: %d", places_debug_menu_timeout_count); \
g_assert(places_debug_menu_timeout_count == 0 || \
places_debug_menu_timeout_count == 1); \
if(pd != NULL){ \
if(places_debug_menu_timeout_count == 0) \
g_assert(pd->menu_timeout_id == 0); \
else \
g_assert(pd->menu_timeout_id > 0); \
} \
}G_STMT_END
#else
#define PLACES_DEBUG_MENU_TIMEOUT_COUNT(delta) \
G_STMT_START{ \
(void) 0; \
}G_STMT_END
#endif
/* UI Helpers */
static void pview_open_menu(PlacesView*);
static void pview_update_menu(PlacesView*);
static void pview_destroy_menu(PlacesView*);
static void pview_button_update(PlacesView*);
/********** Interface for Cfg's Use **********/
inline void
places_view_cfg_iface_update_menu(PlacesViewCfgIface *iface)
{
iface->update_menu(iface->places_view);
}
inline void
places_view_cfg_iface_update_button(PlacesViewCfgIface *iface)
{
iface->update_button(iface->places_view);
}
inline void
places_view_cfg_iface_reconfigure_model(PlacesViewCfgIface *iface)
{
iface->reconfigure_model(iface->places_view);
}
inline GtkWidget*
places_view_cfg_iface_make_empty_cfg_dialog(PlacesViewCfgIface *iface)
{
return iface->make_empty_cfg_dialog(iface->places_view);
}
/********** Model Management **********/
static void
pview_destroy_model(PlacesView *view)
{
GList *bookmark_group_li;
PlacesBookmarkGroup *bookmark_group;
/* we don't want the menu items holding on to any references */
pview_destroy_menu(view);
if(view->bookmark_groups != NULL){
bookmark_group_li = view->bookmark_groups;
do{
if(bookmark_group_li->data != NULL){
bookmark_group = (PlacesBookmarkGroup*) bookmark_group_li->data;
places_bookmark_group_finalize(bookmark_group);
}
bookmark_group_li = bookmark_group_li->next;
}while(bookmark_group_li != NULL);
g_list_free(view->bookmark_groups);
view->bookmark_groups = NULL;
}
}
static void
pview_reconfigure_model(PlacesView *view)
{
pview_destroy_model(view);
/* now re-create it */
view->bookmark_groups = g_list_append(view->bookmark_groups, places_bookmarks_system_create());
if(view->cfg->show_volumes)
view->bookmark_groups = g_list_append(view->bookmark_groups, places_bookmarks_volumes_create(view->cfg->mount_open_volumes));
if(view->cfg->show_bookmarks){
view->bookmark_groups = g_list_append(view->bookmark_groups, NULL); /* separator */
view->bookmark_groups = g_list_append(view->bookmark_groups, places_bookmarks_user_create());
}
}
static gboolean
pview_model_changed(GList *bookmark_groups)
{
gboolean ret = FALSE;
GList *bookmark_group_li = bookmark_groups;
PlacesBookmarkGroup *bookmark_group;
while(bookmark_group_li != NULL){
if(bookmark_group_li->data != NULL){
bookmark_group = (PlacesBookmarkGroup*) bookmark_group_li->data;
ret = places_bookmark_group_changed(bookmark_group) || ret;
}
bookmark_group_li = bookmark_group_li->next;
}
return ret;
}
/********** Gtk Callbacks **********/
/* Panel callbacks */
static gboolean
pview_cb_size_changed(PlacesView *pd)
{
g_assert(pd != NULL);
g_assert(pd->button != NULL);
if(GTK_WIDGET_REALIZED(pd->button))
pview_button_update(pd);
return TRUE;
}
static void
pview_cb_theme_changed(PlacesView *view)
{
g_assert(view != NULL);
g_assert(view->button != NULL);
DBG("theme changed");
/* update the button */
if(GTK_WIDGET_REALIZED(view->button)){
view->force_update_theme = TRUE;
pview_button_update(view);
}
/* force a menu update */
pview_destroy_menu(view);
}
/* Menu callbacks */
static gboolean /* return false to stop calling it */
pview_cb_menu_timeout(PlacesView *pd){
if(!pd->menu_timeout_id)
goto killtimeout;
if(pd->menu == NULL || !GTK_WIDGET_VISIBLE(pd->menu))
goto killtimeout;
if(pview_model_changed(pd->bookmark_groups))
pview_open_menu(pd);
PLACES_DEBUG_MENU_TIMEOUT_COUNT(0);
return TRUE;
killtimeout:
if(pd->menu_timeout_id){
pd->menu_timeout_id = 0;
PLACES_DEBUG_MENU_TIMEOUT_COUNT(-1);
}else{
PLACES_DEBUG_MENU_TIMEOUT_COUNT(0);
}
return FALSE;
}
/* Copied almost verbatim from notes plugin */
static void
pview_cb_menu_position(GtkMenu *menu,
gint *x, gint *y,
gboolean *push_in,
XfcePanelPlugin *plugin)
{
GtkRequisition requisition;
GtkWidget *attach_widget;
g_return_if_fail(GTK_IS_MENU(menu));
g_return_if_fail(XFCE_IS_PANEL_PLUGIN(plugin));
attach_widget = gtk_menu_get_attach_widget(menu);
g_return_if_fail(GTK_IS_WIDGET(attach_widget));
gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
gdk_window_get_origin(attach_widget->window, x, y);
switch(xfce_panel_plugin_get_orientation(plugin))
{
case GTK_ORIENTATION_HORIZONTAL:
if(*y + attach_widget->allocation.height + requisition.height > gdk_screen_height()){
/* Show menu above */
*y -= requisition.height;
}else{
/* Show menu below */
*y += attach_widget->allocation.height;
}
if(*x + requisition.width > gdk_screen_width()){
/* Adjust horizontal position */
*x = gdk_screen_width () - requisition.width;
}
break;
case GTK_ORIENTATION_VERTICAL:
if(*x + attach_widget->allocation.width + requisition.width > gdk_screen_width()){
/* Show menu on the right */
*x -= requisition.width;
}else{
/* Show menu on the left */
*x += attach_widget->allocation.width;
}
if(*y + requisition.height > gdk_screen_height()){
/* Adjust vertical position */
*y = gdk_screen_height() - requisition.height;
}
break;
default:
break;
}
*push_in = FALSE;
}
static void
pview_cb_menu_deact(PlacesView *pd, GtkWidget *menu)
{
/* deactivate button */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->button), FALSE);
/* remove the timeout to save a tick */
if(pd->menu_timeout_id){
g_source_remove(pd->menu_timeout_id);
pd->menu_timeout_id = 0;
PLACES_DEBUG_MENU_TIMEOUT_COUNT(-1);
}else{
PLACES_DEBUG_MENU_TIMEOUT_COUNT(0);
}
}
/* Button */
static gboolean
pview_cb_button_pressed(PlacesView *pd, GdkEventButton *evt)
{
/* (it's the way xfdesktop menu does it...) */
if((evt->state & GDK_CONTROL_MASK) && !(evt->state & (GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK)))
return FALSE;
if(evt->button == 1)
pview_open_menu(pd);
else if(evt->button == 2)
places_load_thunar(NULL);
return FALSE;
}
static void
pview_cb_menu_item_context_act(GtkWidget *item, PlacesView *pd)
{
PlacesBookmarkAction *action;
g_assert(pd != NULL);
g_assert(pd->menu != NULL && GTK_IS_WIDGET(pd->menu));
/* we want the menu gone - now - since it prevents mouse grabs */
gtk_menu_shell_deactivate(GTK_MENU_SHELL(pd->menu));
while(g_main_context_iteration(NULL, FALSE))
/* no op */;
action = (PlacesBookmarkAction*) g_object_get_data(G_OBJECT(item), "action");
DBG("Calling action %s", action->label);
places_bookmark_action_call(action);
}
static gboolean
pview_cb_menu_item_do_alt(PlacesView *pd, GtkWidget *menu_item)
{
PlacesBookmark *bookmark = (PlacesBookmark*) g_object_get_data(G_OBJECT(menu_item), "bookmark");
GList *actions = bookmark->actions;
GtkWidget *context, *context_item;
PlacesBookmarkAction *action;
if(actions != NULL){
context = gtk_menu_new();
do{
action = (PlacesBookmarkAction*) actions->data;
context_item = gtk_menu_item_new_with_label(action->label);
g_object_set_data(G_OBJECT(context_item), "action", action);
g_signal_connect(context_item, "activate",
G_CALLBACK(pview_cb_menu_item_context_act), pd);
gtk_menu_shell_append(GTK_MENU_SHELL(context), context_item);
gtk_widget_show(context_item);
actions = actions->next;
}while(actions != NULL);
gtk_widget_show(context);
gtk_menu_popup(GTK_MENU(context),
NULL, NULL,
NULL, NULL,
0, gtk_get_current_event_time());
g_signal_connect_swapped(context, "deactivate",
G_CALLBACK(pview_open_menu), pd);
}
return TRUE;
}
static gboolean
pview_cb_menu_item_press(GtkWidget *menu_item, GdkEventButton *event, PlacesView *pd)
{
gboolean ctrl = (event->state & GDK_CONTROL_MASK) &&
!(event->state & (GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK));
PlacesBookmark *bookmark = (PlacesBookmark*) g_object_get_data(G_OBJECT(menu_item), "bookmark");
if(event->button == 3 || (event->button == 1 && (ctrl || bookmark->primary_action == NULL)))
return pview_cb_menu_item_do_alt(pd, menu_item);
else
return FALSE;
}
/* Recent Documents */
#if USE_RECENT_DOCUMENTS
static void
pview_cb_recent_item_open(GtkRecentChooser *chooser, PlacesView *pd)
{
gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
places_load_file(uri);
g_free(uri);
}
static gboolean
pview_cb_recent_items_clear(GtkWidget *clear_item)
{
GtkRecentManager *manager = gtk_recent_manager_get_default();
gint removed = gtk_recent_manager_purge_items(manager, NULL);
DBG("Cleared %d recent items", removed);
return TRUE;
}
#endif
/********** UI Helpers **********/
static void
pview_destroy_menu(PlacesView *view)
{
if(view->menu != NULL){
gtk_menu_shell_deactivate(GTK_MENU_SHELL(view->menu));
gtk_widget_destroy(view->menu);
view->menu = NULL;
}
view->needs_separator = FALSE;
}
static void
pview_add_menu_item(PlacesView *view, PlacesBookmark *bookmark)
{
g_assert(view != NULL);
g_assert(bookmark != NULL);
GtkWidget *separator;
GtkWidget *item;
GdkPixbuf *pb;
GtkWidget *image;
/* lazily add separator */
if(view->needs_separator){
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(view->menu), separator);
gtk_widget_show(separator);
view->needs_separator = FALSE;
}
item = gtk_image_menu_item_new_with_label(bookmark->label);
/* try to set icon */
if(view->cfg->show_icons && bookmark->icon != NULL){
pb = xfce_themed_icon_load(bookmark->icon, 16);
if(G_LIKELY(pb != NULL)){
image = gtk_image_new_from_pixbuf(pb);
g_object_unref(pb);
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
}
}
g_object_set_data(G_OBJECT(item), "bookmark", bookmark);
/* do this always so that the menu doesn't close on right-clicks */
g_signal_connect(item, "button-release-event",
G_CALLBACK(pview_cb_menu_item_press), view);
if(bookmark->primary_action != NULL){
g_signal_connect_swapped(item, "activate",
G_CALLBACK(places_bookmark_action_call),
bookmark->primary_action);
}
if(bookmark->force_gray || bookmark->primary_action == NULL){
/* Gray it out. */
gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(item)),
FALSE);
}
g_signal_connect_swapped(item, "destroy",
G_CALLBACK(places_bookmark_free), bookmark);
gtk_menu_shell_append(GTK_MENU_SHELL(view->menu), item);
gtk_widget_show(item);
}
static void
pview_update_menu(PlacesView *pd)
{
GList *bookmark_group_li;
PlacesBookmarkGroup *bookmark_group;
GList *bookmarks;
PlacesBookmark *bookmark;
GtkWidget *separator;
#if USE_RECENT_DOCUMENTS
GtkWidget *recent_menu;
GtkWidget *clear_item;
GtkWidget *recent_item;
#endif
DBG("destroy menu");
/* destroy the old menu, if it exists */
pview_destroy_menu(pd);
DBG("building new menu");
/* Create a new menu */
pd->menu = gtk_menu_new();
/* make sure the menu popups up in right screen */
gtk_menu_attach_to_widget(GTK_MENU(pd->menu), pd->button, NULL);
gtk_menu_set_screen(GTK_MENU(pd->menu),
gtk_widget_get_screen(pd->button));
/* add bookmarks */
bookmark_group_li = pd->bookmark_groups;
while(bookmark_group_li != NULL){
if(bookmark_group_li->data == NULL){ /* separator */
pd->needs_separator = TRUE;
}else{
bookmark_group = (PlacesBookmarkGroup*) bookmark_group_li->data;
bookmarks = places_bookmark_group_get_bookmarks(bookmark_group);
while(bookmarks != NULL){
bookmark = (PlacesBookmark*) bookmarks->data;
pview_add_menu_item(pd, bookmark);
bookmarks = bookmarks->next;
}
g_list_free(bookmarks);
}
bookmark_group_li = bookmark_group_li->next;
}
/* "Search for Files" or "Recent Documents" -> separator */
#if USE_RECENT_DOCUMENTS
if(pd->cfg->show_recent || (pd->cfg->search_cmd != NULL && *pd->cfg->search_cmd != '\0')){
#else
if(pd->cfg->search_cmd != NULL && *pd->cfg->search_cmd != '\0'){
#endif
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(pd->menu), separator);
gtk_widget_show(separator);
}
/* Search for files */
if(pd->cfg->search_cmd != NULL && *pd->cfg->search_cmd != '\0'){
GtkWidget *search_item = gtk_image_menu_item_new_with_mnemonic(_("Search for Files"));
if(pd->cfg->show_icons){
GtkWidget *search_image = gtk_image_new_from_icon_name("system-search", GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(search_item), search_image);
}
gtk_menu_shell_append(GTK_MENU_SHELL(pd->menu), search_item);
gtk_widget_show(search_item);
g_signal_connect_swapped(search_item, "activate",
G_CALLBACK(places_gui_exec), pd->cfg->search_cmd);
}
/* Recent Documents */
#if USE_RECENT_DOCUMENTS
if(pd->cfg->show_recent){
recent_menu = gtk_recent_chooser_menu_new();
gtk_recent_chooser_set_show_icons(GTK_RECENT_CHOOSER(recent_menu), pd->cfg->show_icons);
gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(recent_menu), pd->cfg->show_recent_number);
g_signal_connect(recent_menu, "item-activated",
G_CALLBACK(pview_cb_recent_item_open), pd);
if(pd->cfg->show_recent_clear){
separator = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(recent_menu), separator);
gtk_widget_show(separator);
if(pd->cfg->show_icons){
clear_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
}else{
GtkStockItem clear_stock_item;
gtk_stock_lookup(GTK_STOCK_CLEAR, &clear_stock_item);
clear_item = gtk_menu_item_new_with_mnemonic(clear_stock_item.label);
}
gtk_menu_shell_append(GTK_MENU_SHELL(recent_menu), clear_item);
gtk_widget_show(clear_item);
/* try button-release-event to catch mouse clicks and not hide the menu after */
g_signal_connect(clear_item, "button-release-event",
G_CALLBACK(pview_cb_recent_items_clear), NULL);
/* use activate when button-release-event doesn't catch it (e.g., enter key pressed) */
g_signal_connect(clear_item, "activate",
G_CALLBACK(pview_cb_recent_items_clear), NULL);
}
recent_item = gtk_image_menu_item_new_with_label(_("Recent Documents"));
if(pd->cfg->show_icons){
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(recent_item),
gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
}
gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu);
gtk_widget_show(recent_menu);
gtk_menu_shell_append(GTK_MENU_SHELL(pd->menu), recent_item);
gtk_widget_show(recent_item);
}
#endif
/* connect deactivate signal */
g_signal_connect_swapped(pd->menu, "deactivate",
G_CALLBACK(pview_cb_menu_deact), pd);
/* Quit hiding the menu */
gtk_widget_show(pd->menu);
/* This helps allocate resources beforehand so it'll pop up faster the first time */
gtk_widget_realize(pd->menu);
}
static void
pview_open_menu(PlacesView *pd)
{
/* check if menu is needed, or it needs an update */
if(pd->menu == NULL || pview_model_changed(pd->bookmark_groups))
pview_update_menu(pd);
/* toggle the button */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->button), TRUE);
/* Register this menu (for focus, transparency, auto-hide, etc) */
/* We don't want to register if the menu is visible (hasn't been deactivated) */
if(!GTK_WIDGET_VISIBLE(pd->menu))
xfce_panel_plugin_register_menu(pd->plugin, GTK_MENU(pd->menu));
/* popup menu */
gtk_menu_popup (GTK_MENU (pd->menu), NULL, NULL,
(GtkMenuPositionFunc) pview_cb_menu_position,
pd->plugin, 0,
gtk_get_current_event_time ());
/* menu timeout to poll for model changes */
if(pd->menu_timeout_id == 0){
#if GLIB_CHECK_VERSION(2,14,0)
pd->menu_timeout_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 2,
(GSourceFunc) pview_cb_menu_timeout, pd,
NULL);
#else
pd->menu_timeout_id = g_timeout_add_full(G_PRIORITY_LOW, 2000,
(GSourceFunc) pview_cb_menu_timeout, pd,
NULL);
#endif
PLACES_DEBUG_MENU_TIMEOUT_COUNT(1);
}else{
PLACES_DEBUG_MENU_TIMEOUT_COUNT(0);
}
}
static void
pview_button_update(PlacesView *view)
{
PlacesCfg *cfg = view->cfg;
gboolean orientation_changed, size_changed,
icon_presence_changed, label_presence_changed,
label_tooltip_changed, theme_changed;
static gboolean first_run = TRUE;
DBG("button_update (first run: %1x)", first_run);
if(first_run){
first_run = FALSE;
orientation_changed = TRUE;
view->orientation = xfce_panel_plugin_get_orientation(view->plugin);
size_changed = TRUE;
view->size = xfce_panel_plugin_get_size(view->plugin);
icon_presence_changed = TRUE;
view->show_button_icon = cfg->show_button_icon;
label_presence_changed = TRUE;
view->show_button_label = cfg->show_button_label;
label_tooltip_changed = TRUE;
view->label_tooltip_text = g_strdup(cfg->label);
theme_changed = TRUE;
view->force_update_theme = FALSE;
}else{
orientation_changed = (view->orientation != xfce_panel_plugin_get_orientation(view->plugin));
size_changed = (view->size != xfce_panel_plugin_get_size(view->plugin));
icon_presence_changed = (view->show_button_icon != cfg->show_button_icon);
label_presence_changed = (view->show_button_label != cfg->show_button_label);
label_tooltip_changed = (strcmp(view->label_tooltip_text, cfg->label) != 0);
theme_changed = view->force_update_theme;
}
DBG("orientation: %1x, size: %1x, icon_pr: %1x, label_pr: %1x, label_tooltip: %1x",
orientation_changed, size_changed,
icon_presence_changed, label_presence_changed,
label_tooltip_changed);
if(orientation_changed){
GtkWidget *button_box = gtk_bin_get_child(GTK_BIN(view->button));
view->orientation = xfce_panel_plugin_get_orientation(view->plugin);
xfce_hvbox_set_orientation(XFCE_HVBOX(button_box), view->orientation);
size_changed = TRUE;
}
if(label_tooltip_changed){
g_free(view->label_tooltip_text);
view->label_tooltip_text = g_strdup(cfg->label);
}
if(theme_changed)
view->force_update_theme = FALSE;
if(size_changed || icon_presence_changed || label_presence_changed || theme_changed){
view->size = xfce_panel_plugin_get_size(view->plugin);
DBG("Panel size: %d", view->size);
view->show_button_icon = cfg->show_button_icon;
view->show_button_label = cfg->show_button_label;
GdkPixbuf *icon;
gint width, height;
gint button_overhead_size, box_overhead_size;
GtkWidget *button_box = gtk_bin_get_child(GTK_BIN(view->button));
button_overhead_size = 2 + 2 * MAX(view->button->style->xthickness,
view->button->style->ythickness);
box_overhead_size = 0;
width = 0;
height = 0;
if(view->show_button_icon){
icon = xfce_themed_icon_load_category(2, view->size - button_overhead_size);
if(G_LIKELY(icon != NULL)){
width = MAX(gdk_pixbuf_get_width(icon), view->size - button_overhead_size);
height = MAX(gdk_pixbuf_get_height(icon), view->size - button_overhead_size);
if(view->button_image == NULL){
view->button_image = g_object_ref(gtk_image_new_from_pixbuf(icon));
gtk_box_pack_start_defaults(GTK_BOX(button_box),
view->button_image);
gtk_widget_show(view->button_image);
}else{
g_assert(GTK_IS_WIDGET(view->button_image));
gtk_image_set_from_pixbuf(GTK_IMAGE(view->button_image), icon);
}
g_object_unref(G_OBJECT(icon));
}else{
DBG("Could not load icon for button");
}
}else if(view->button_image != NULL){
g_assert(GTK_IS_WIDGET(view->button_image));
gtk_widget_destroy(view->button_image);
g_object_unref(view->button_image);
view->button_image = NULL;
}
if(view->show_button_label){
GtkRequisition req;
if(view->button_label == NULL){
view->button_label = g_object_ref(gtk_label_new(cfg->label));
gtk_box_pack_end_defaults(GTK_BOX(button_box),
view->button_label);
gtk_widget_show(view->button_label);
}else{
g_assert(GTK_IS_WIDGET(view->button_label));
if(label_tooltip_changed)
gtk_label_set_text(GTK_LABEL(view->button_label), view->label_tooltip_text);
}
gtk_widget_size_request(view->button_label, &req);
if(view->orientation == GTK_ORIENTATION_HORIZONTAL){
width += req.width;
height = MAX(height, req.height);
}else{
width = MAX(width, req.width);
height += req.height;
}
}else if(view->button_label != NULL){
g_assert(GTK_IS_WIDGET(view->button_label));
gtk_widget_destroy(view->button_label);
g_object_unref(view->button_label);
view->button_label = NULL;
}
width += button_overhead_size;
height += button_overhead_size;
if(view->button_image != NULL && view->button_label != NULL){
box_overhead_size = gtk_box_get_spacing(GTK_BOX(button_box));
if(view->orientation == GTK_ORIENTATION_HORIZONTAL)
width += box_overhead_size;
else
height += box_overhead_size;
}
if(view->orientation == GTK_ORIENTATION_HORIZONTAL)
height = MAX(height, view->size);
else
width = MAX(width, view->size);
gtk_widget_show_all(view->button);
DBG("width=%d, height=%d", width, height);
gtk_widget_set_size_request(view->button, width, height);
}
if(label_tooltip_changed)
gtk_tooltips_set_tip(view->tooltips, view->button, view->label_tooltip_text, NULL);
}
static void
pview_cfg_dialog_close_cb(GtkDialog *dialog, gint response, PlacesView *view)
{
gtk_widget_destroy(GTK_WIDGET(dialog));
xfce_panel_plugin_unblock_menu(view->plugin);
places_cfg_view_iface_save(view->cfg_iface);
}
static GtkWidget*
pview_make_empty_cfg_dialog(PlacesView *view)
{
GtkWidget *dlg; /* we'll return this */
xfce_panel_plugin_block_menu(view->plugin);
dlg = xfce_titled_dialog_new_with_buttons(_("Places"),
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view->plugin))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL);
gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
gtk_window_set_icon_name(GTK_WINDOW(dlg), "xfce4-settings");
g_signal_connect(dlg, "response",
G_CALLBACK(pview_cfg_dialog_close_cb), view);
return dlg;
}
/********** Initialization & Finalization **********/
PlacesView*
places_view_init(XfcePanelPlugin *plugin)
{
GtkWidget *button_box;
PlacesView *view; /* internal use in this file */
PlacesViewCfgIface *view_cfg_iface; /* given to cfg */
DBG("initializing");
g_assert(plugin != NULL);
view = g_new0(PlacesView, 1);
view->plugin = plugin;
view_cfg_iface = g_new0(PlacesViewCfgIface, 1);
view_cfg_iface->places_view = view;
view_cfg_iface->update_menu = pview_update_menu;
view_cfg_iface->update_button = pview_button_update;
view_cfg_iface->reconfigure_model = pview_reconfigure_model;
view_cfg_iface->make_empty_cfg_dialog = pview_make_empty_cfg_dialog;
view->view_cfg_iface = view_cfg_iface;
view->cfg_iface = places_cfg_new(view_cfg_iface,
xfce_panel_plugin_lookup_rc_file(view->plugin),
xfce_panel_plugin_save_location(view->plugin, TRUE));
view->cfg = places_cfg_view_iface_get_cfg(view->cfg_iface);
pview_reconfigure_model(view);
view->tooltips = g_object_ref_sink(gtk_tooltips_new());
/* init button */
DBG("init GUI");
/* create the button */
view->button = g_object_ref(xfce_create_panel_toggle_button());
xfce_panel_plugin_add_action_widget(view->plugin, view->button);
gtk_container_add(GTK_CONTAINER(view->plugin), view->button);
gtk_widget_show(view->button);
/* create the box */
button_box = xfce_hvbox_new(xfce_panel_plugin_get_orientation(view->plugin),
FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(button_box), 0);
gtk_container_add(GTK_CONTAINER(view->button), button_box);
gtk_widget_show(button_box);
pview_button_update(view);
/* signals for icon theme/screen changes */
g_signal_connect_swapped(view->button, "style-set",
G_CALLBACK(pview_cb_theme_changed), view);
g_signal_connect_swapped(view->button, "screen-changed",
G_CALLBACK(pview_cb_theme_changed), view);
/* plugin signals */
g_signal_connect_swapped(G_OBJECT(view->plugin), "size-changed",
G_CALLBACK(pview_cb_size_changed), view);
g_signal_connect_swapped(G_OBJECT(view->plugin), "orientation-changed",
G_CALLBACK(pview_button_update), view);
/* button signal */
g_signal_connect_swapped(view->button, "button-press-event",
G_CALLBACK(pview_cb_button_pressed), view);
/* cfg-related signals */
g_signal_connect_swapped(G_OBJECT(view->plugin), "configure-plugin",
G_CALLBACK(places_cfg_view_iface_open_dialog), view->cfg_iface);
g_signal_connect_swapped(G_OBJECT(view->plugin), "save",
G_CALLBACK(places_cfg_view_iface_save), view->cfg_iface);
xfce_panel_plugin_menu_show_configure(view->plugin);
DBG("done");
return view;
}
void
places_view_finalize(PlacesView *view)
{
pview_destroy_menu(view);
pview_destroy_model(view);
if(view->button_image != NULL)
g_object_unref(view->button_image);
if(view->button_label != NULL)
g_object_unref(view->button_label);
if(view->button != NULL)
g_object_unref(view->button);
if(view->label_tooltip_text != NULL)
g_free(view->label_tooltip_text);
g_object_unref(view->tooltips);
places_cfg_view_iface_finalize(view->cfg_iface);
g_free(view->view_cfg_iface);
g_free(view);
}
/* vim: set ai et tabstop=4: */
syntax highlighted by Code2HTML, v. 0.9.1