3
* Copyright (c) 2007 Diego Ongaro <ongardie@gmail.com>
7
* - xfdesktop menu plugin
8
* desktop-menu-plugin.c - xfce4-panel plugin that displays the desktop menu
9
* Copyright (C) 2004 Brian Tarricone, <bjt23@cornell.edu>
12
* launcher.c - (xfce4-panel plugin that opens programs)
13
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
14
* Copyright (c) 2006-2007 Nick Schermer <nick@xfce.org>
16
* This program is free software; you can redistribute it and/or modify
17
* it under the terms of the GNU General Public License as published by
18
* the Free Software Foundation; either version 2 of the License, or
19
* (at your option) any later version.
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU Library General Public License for more details.
26
* You should have received a copy of the GNU General Public License
27
* along with this program; if not, write to the Free Software
28
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37
#include <libxfce4panel/xfce-panel-plugin.h>
38
#include <libxfce4panel/xfce-panel-convenience.h>
39
#include <libxfcegui4/libxfcegui4.h>
45
#if GTK_CHECK_VERSION(2,10,0)
46
# define USE_RECENT_DOCUMENTS TRUE
50
static void places_view_update_menu(PlacesData*);
51
static void places_view_open_menu(PlacesData*);
52
static void places_view_destroy_menu(PlacesData*);
53
static void places_view_button_update(PlacesData*);
58
static gboolean places_view_cb_size_changed(PlacesData*, guint size);
59
static gboolean places_view_cb_theme_changed(GSignalInvocationHint*,
60
guint n_param_values, const GValue *param_values,
64
static void places_view_cb_menu_position(GtkMenu*,
68
static void places_view_cb_menu_deact(PlacesData*, GtkWidget *menu);
69
static void places_view_cb_menu_item_open(GtkWidget *item, const gchar *uri);
72
static gboolean places_view_cb_button_pressed(PlacesData*, GdkEventButton *);
75
#if USE_RECENT_DOCUMENTS
76
static void places_view_cb_recent_item_open(GtkRecentChooser*, PlacesData*);
77
static void places_view_cb_recent_items_clear(GtkWidget *clear_item);
80
// Model Visitor Callbacks
81
static void places_view_add_menu_item(gpointer _places_data,
82
const gchar *label, const gchar *uri, const gchar *icon);
83
static void places_view_add_menu_sep(gpointer _places_data);
86
/********** Initialization & Finalization **********/
89
places_view_init(PlacesData *pd)
93
gpointer icon_theme_class;
97
pd->view_tooltips = g_object_ref_sink(gtk_tooltips_new());
100
pd->view_button = xfce_create_panel_toggle_button();
101
gtk_widget_show (pd->view_button);
102
gtk_container_add(GTK_CONTAINER(pd->plugin), pd->view_button);
103
gtk_button_set_focus_on_click(GTK_BUTTON(pd->view_button), FALSE);
104
gtk_tooltips_set_tip(pd->view_tooltips, pd->view_button, _("Places"), NULL);
106
pd->view_button_image = gtk_image_new();
107
gtk_widget_show(pd->view_button_image);
108
gtk_container_add(GTK_CONTAINER(pd->view_button), pd->view_button_image);
110
xfce_panel_plugin_add_action_widget(pd->plugin, pd->view_button);
113
// signal for icon theme changes
114
icon_theme_class = g_type_class_ref(GTK_TYPE_ICON_THEME);
115
pd->view_theme_timeout_id = g_signal_add_emission_hook(g_signal_lookup("changed", GTK_TYPE_ICON_THEME),
116
0, (GSignalEmissionHook) places_view_cb_theme_changed,
118
g_type_class_unref(icon_theme_class);
121
// connect the signals
122
g_signal_connect_swapped(pd->view_button, "button-press-event",
123
G_CALLBACK(places_view_cb_button_pressed), pd);
125
g_signal_connect_swapped(G_OBJECT(pd->plugin), "size-changed",
126
G_CALLBACK(places_view_cb_size_changed), pd);
131
places_view_finalize(PlacesData *pd)
133
places_view_destroy_menu(pd);
134
g_signal_remove_emission_hook(g_signal_lookup("changed", GTK_TYPE_ICON_THEME),
135
pd->view_theme_timeout_id);
136
g_object_unref(pd->view_tooltips);
139
/********** UI Helpers **********/
142
places_view_update_menu(PlacesData *pd)
144
BookmarksVisitor visitor;
145
#if USE_RECENT_DOCUMENTS
146
GtkWidget *recent_menu;
147
GtkWidget *clear_item;
148
GtkWidget *recent_item;
151
/* destroy the old menu, if it exists */
152
places_view_destroy_menu(pd);
155
pd->view_menu = gtk_menu_new();
157
/* make sure the menu popups up in right screen */
158
gtk_menu_set_screen (GTK_MENU (pd->view_menu),
159
gtk_widget_get_screen (GTK_WIDGET (pd->plugin)));
162
// Add system, volumes, user bookmarks
163
visitor.pass_thru = pd;
164
visitor.item = places_view_add_menu_item;
165
visitor.separator = places_view_add_menu_sep;
166
places_bookmarks_visit(pd->bookmarks, &visitor);
169
#if USE_RECENT_DOCUMENTS
170
places_view_add_menu_sep(pd);
172
recent_menu = gtk_recent_chooser_menu_new();
173
g_signal_connect(recent_menu, "item-activated",
174
G_CALLBACK(places_view_cb_recent_item_open), pd);
176
gtk_menu_shell_append(GTK_MENU_SHELL(recent_menu),
177
gtk_separator_menu_item_new());
178
clear_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
179
gtk_menu_shell_append(GTK_MENU_SHELL(recent_menu), clear_item);
180
g_signal_connect(clear_item, "activate",
181
G_CALLBACK(places_view_cb_recent_items_clear), NULL);
183
recent_item = gtk_image_menu_item_new_with_label(_("Recent Documents"));
184
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(recent_item),
185
gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
186
gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu);
187
gtk_menu_shell_append(GTK_MENU_SHELL(pd->view_menu), recent_item);
190
/* connect deactivate signal */
191
g_signal_connect_swapped(pd->view_menu, "deactivate",
192
G_CALLBACK(places_view_cb_menu_deact), pd);
194
// Quit hiding the menu
195
gtk_widget_show_all(pd->view_menu);
197
// This helps allocate resources beforehand so it'll pop up faster the first time
198
gtk_widget_realize(pd->view_menu);
203
places_view_open_menu(PlacesData *pd)
205
/* check if menu is needed, or it needs an update */
206
if(pd->view_menu == NULL || places_bookmarks_changed(pd->bookmarks))
207
places_view_update_menu(pd);
209
/* toggle the button */
210
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pd->view_button), TRUE);
212
// Register this menu (for focus, transparency, auto-hide, etc)
213
xfce_panel_plugin_register_menu(pd->plugin, GTK_MENU(pd->view_menu));
216
gtk_menu_popup (GTK_MENU (pd->view_menu), NULL, NULL,
217
(GtkMenuPositionFunc) places_view_cb_menu_position,
219
gtk_get_current_event_time ());
223
places_view_destroy_menu(PlacesData *pd)
225
if(pd->view_menu != NULL){
226
g_signal_emit_by_name(G_OBJECT(pd->view_menu), "deactivate");
227
gtk_widget_destroy(pd->view_menu);
228
pd->view_menu = NULL;
233
places_view_button_update(PlacesData *pd)
238
size = xfce_panel_plugin_get_size(XFCE_PANEL_PLUGIN(pd->plugin))
239
- 2 - 2 * MAX(pd->view_button->style->xthickness,
240
pd->view_button->style->ythickness);
242
icon = xfce_themed_icon_load_category(2, size);
243
if(G_LIKELY(icon != NULL)){
245
gtk_image_set_from_pixbuf(GTK_IMAGE(pd->view_button_image), icon);
246
g_object_unref(G_OBJECT(icon));
249
// I'd use this, but it's new in gtk 2.8:
250
// gtk_image_clear(GTK_IMAGE(pd->view_button_image));
252
gtk_widget_destroy(pd->view_button_image);
253
pd->view_button_image = gtk_image_new();
254
gtk_widget_show(pd->view_button_image);
255
gtk_container_add(GTK_CONTAINER(pd->view_button), pd->view_button_image);
260
/********** Gtk Callbacks **********/
265
places_view_cb_size_changed(PlacesData *pd, guint size)
267
gtk_widget_set_size_request(pd->view_button, size, size);
269
if(GTK_WIDGET_REALIZED(pd->view_button))
270
places_view_button_update(pd);
276
places_view_cb_theme_changed(GSignalInvocationHint *ihint,
277
guint n_param_values, const GValue *param_values,
281
if(GTK_WIDGET_REALIZED(pd->view_button))
282
places_view_button_update(pd);
284
// force a menu update
285
places_view_destroy_menu(pd);
292
/* Copied almost verbatim from xfdesktop plugin */
294
places_view_cb_menu_position(GtkMenu *menu,
299
XfceScreenPosition pos;
302
gtk_widget_size_request(GTK_WIDGET(menu), &req);
304
gdk_window_get_origin (GTK_WIDGET (pd->plugin)->window, x, y);
306
pos = xfce_panel_plugin_get_screen_position(pd->plugin);
309
case XFCE_SCREEN_POSITION_NW_V:
310
case XFCE_SCREEN_POSITION_W:
311
case XFCE_SCREEN_POSITION_SW_V:
312
*x += pd->view_button->allocation.width;
313
*y += pd->view_button->allocation.height - req.height;
316
case XFCE_SCREEN_POSITION_NE_V:
317
case XFCE_SCREEN_POSITION_E:
318
case XFCE_SCREEN_POSITION_SE_V:
320
*y += pd->view_button->allocation.height - req.height;
323
case XFCE_SCREEN_POSITION_NW_H:
324
case XFCE_SCREEN_POSITION_N:
325
case XFCE_SCREEN_POSITION_NE_H:
326
*y += pd->view_button->allocation.height;
329
case XFCE_SCREEN_POSITION_SW_H:
330
case XFCE_SCREEN_POSITION_S:
331
case XFCE_SCREEN_POSITION_SE_H:
335
default: /* floating */
337
GdkScreen *screen = NULL;
338
gint screen_width, screen_height;
340
gdk_display_get_pointer(gtk_widget_get_display(GTK_WIDGET(pd->plugin)),
341
&screen, x, y, NULL);
342
screen_width = gdk_screen_get_width(screen);
343
screen_height = gdk_screen_get_height(screen);
344
if ((*x + req.width) > screen_width)
346
if ((*y + req.height) > screen_height)
357
/* "wtf is this ?" -Xfdesktop source */
362
places_view_cb_menu_deact(PlacesData *pd, GtkWidget *menu)
365
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->view_button), FALSE);
369
places_view_cb_menu_item_open(GtkWidget *widget, const gchar* uri)
371
places_load_thunar(uri);
376
places_view_cb_button_pressed(PlacesData *pd, GdkEventButton *evt)
378
// (it's the way xfdesktop menu does it...)
379
if(evt->button != 1 || ((evt->state & GDK_CONTROL_MASK)
380
&& !(evt->state & (GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK))))
383
places_view_open_menu(pd);
390
#if USE_RECENT_DOCUMENTS
392
places_view_cb_recent_item_open(GtkRecentChooser *chooser, PlacesData *pd)
394
gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
395
places_load_thunar(uri);
400
places_view_cb_recent_items_clear(GtkWidget *clear_item)
402
GtkRecentManager *manager = gtk_recent_manager_get_default();
403
gint removed = gtk_recent_manager_purge_items(manager, NULL);
404
DBG("Cleared %d recent items", removed);
408
/********** Model Visitor Callbacks **********/
411
places_view_add_menu_item(gpointer _pd, const gchar *label, const gchar *uri, const gchar *icon)
413
g_assert(_pd != NULL);
414
g_return_if_fail(label != NULL && label != "");
415
g_return_if_fail(uri != NULL && uri != "");
417
PlacesData *pd = (PlacesData*) _pd;
418
GtkWidget *item = gtk_image_menu_item_new_with_label(label);
420
if(G_LIKELY(icon != NULL)){
421
GdkPixbuf *pb = xfce_themed_icon_load(icon, 16);
423
if(G_LIKELY(pb != NULL)){
424
GtkWidget *image = gtk_image_new_from_pixbuf(pb);
426
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
430
g_signal_connect(item, "activate",
431
G_CALLBACK(places_view_cb_menu_item_open), (gchar*) uri);
432
gtk_menu_shell_append(GTK_MENU_SHELL(pd->view_menu), item);
436
places_view_add_menu_sep(gpointer _pd)
438
g_assert(_pd != NULL);
439
PlacesData *pd = (PlacesData*) _pd;
441
gtk_menu_shell_append(GTK_MENU_SHELL(pd->view_menu),
442
gtk_separator_menu_item_new());
445
// vim: ai et tabstop=4