~jan-hrdina/ubuntu/quantal/xfce4-places-plugin/1.4.0-upstream-import

« back to all changes in this revision

Viewing changes to panel-plugin/view.c

  • Committer: Bazaar Package Importer
  • Author(s): Gauvain Pocentek
  • Date: 2007-04-22 08:55:28 UTC
  • Revision ID: james.westby@ubuntu.com-20070422085528-ijr73vydcqg5l830
Tags: upstream-0.2.0
ImportĀ upstreamĀ versionĀ 0.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  xfce4-places-plugin
 
2
 *
 
3
 *  Copyright (c) 2007 Diego Ongaro <ongardie@gmail.com>
 
4
 *
 
5
 *  Largely based on:
 
6
 *
 
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>
 
10
 *  
 
11
 *   - launcher plugin
 
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>
 
15
 *
 
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.
 
20
 *
 
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.
 
25
 *
 
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.
 
29
 */
 
30
 
 
31
#ifdef HAVE_CONFIG_H
 
32
#  include <config.h>
 
33
#endif
 
34
 
 
35
#include <gtk/gtk.h>
 
36
 
 
37
#include <libxfce4panel/xfce-panel-plugin.h>
 
38
#include <libxfce4panel/xfce-panel-convenience.h>
 
39
#include <libxfcegui4/libxfcegui4.h>
 
40
 
 
41
#include "view.h"
 
42
#include "places.h"
 
43
#include "model.h"
 
44
 
 
45
#if GTK_CHECK_VERSION(2,10,0)
 
46
#  define USE_RECENT_DOCUMENTS TRUE
 
47
#endif
 
48
 
 
49
// UI Helpers
 
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*);
 
54
 
 
55
// GTK Callbacks
 
56
 
 
57
//  - Panel
 
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,
 
61
                             PlacesData*);
 
62
 
 
63
//  - Menu
 
64
static void     places_view_cb_menu_position(GtkMenu*, 
 
65
                                             gint *x, gint *y, 
 
66
                                             gboolean *push_in, 
 
67
                                             PlacesData*);
 
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);
 
70
 
 
71
//  - Button
 
72
static gboolean places_view_cb_button_pressed(PlacesData*, GdkEventButton *);
 
73
 
 
74
//  - Recent Documents
 
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);
 
78
#endif
 
79
 
 
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);
 
84
 
 
85
 
 
86
/********** Initialization & Finalization **********/
 
87
 
 
88
void
 
89
places_view_init(PlacesData *pd)
 
90
{
 
91
    DBG("initializing");
 
92
    
 
93
    gpointer icon_theme_class;
 
94
 
 
95
    pd->view_menu = NULL;
 
96
 
 
97
    pd->view_tooltips = g_object_ref_sink(gtk_tooltips_new());
 
98
 
 
99
    // init button
 
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);
 
105
    
 
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);
 
109
 
 
110
    xfce_panel_plugin_add_action_widget(pd->plugin, pd->view_button);
 
111
 
 
112
 
 
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,
 
117
                                                            pd, NULL);
 
118
    g_type_class_unref(icon_theme_class);
 
119
   
 
120
    
 
121
    // connect the signals
 
122
    g_signal_connect_swapped(pd->view_button, "button-press-event",
 
123
                             G_CALLBACK(places_view_cb_button_pressed), pd);
 
124
 
 
125
    g_signal_connect_swapped(G_OBJECT(pd->plugin), "size-changed",
 
126
                             G_CALLBACK(places_view_cb_size_changed), pd);
 
127
}
 
128
 
 
129
 
 
130
void 
 
131
places_view_finalize(PlacesData *pd)
 
132
{
 
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);
 
137
}
 
138
 
 
139
/********** UI Helpers **********/
 
140
 
 
141
static void
 
142
places_view_update_menu(PlacesData *pd)
 
143
{
 
144
    BookmarksVisitor visitor;
 
145
#if USE_RECENT_DOCUMENTS
 
146
    GtkWidget *recent_menu;
 
147
    GtkWidget *clear_item;
 
148
    GtkWidget *recent_item;
 
149
#endif
 
150
 
 
151
    /* destroy the old menu, if it exists */
 
152
    places_view_destroy_menu(pd);
 
153
 
 
154
    // Create a new menu
 
155
    pd->view_menu = gtk_menu_new();
 
156
    
 
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)));
 
160
 
 
161
 
 
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);
 
167
 
 
168
    // Recent Documents
 
169
#if USE_RECENT_DOCUMENTS
 
170
    places_view_add_menu_sep(pd);
 
171
 
 
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);
 
175
 
 
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);
 
182
    
 
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);
 
188
#endif
 
189
 
 
190
    /* connect deactivate signal */
 
191
    g_signal_connect_swapped(pd->view_menu, "deactivate",
 
192
                             G_CALLBACK(places_view_cb_menu_deact), pd);
 
193
 
 
194
    // Quit hiding the menu
 
195
    gtk_widget_show_all(pd->view_menu);
 
196
 
 
197
    // This helps allocate resources beforehand so it'll pop up faster the first time
 
198
    gtk_widget_realize(pd->view_menu);
 
199
}
 
200
 
 
201
 
 
202
static void
 
203
places_view_open_menu(PlacesData *pd)
 
204
{
 
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);
 
208
 
 
209
    /* toggle the button */
 
210
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pd->view_button), TRUE);
 
211
 
 
212
    // Register this menu (for focus, transparency, auto-hide, etc)
 
213
    xfce_panel_plugin_register_menu(pd->plugin, GTK_MENU(pd->view_menu));
 
214
 
 
215
    /* popup menu */
 
216
    gtk_menu_popup (GTK_MENU (pd->view_menu), NULL, NULL,
 
217
                    (GtkMenuPositionFunc) places_view_cb_menu_position,
 
218
                    pd, 0,
 
219
                    gtk_get_current_event_time ());
 
220
}
 
221
 
 
222
static void
 
223
places_view_destroy_menu(PlacesData *pd)
 
224
{
 
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;
 
229
    }
 
230
}
 
231
 
 
232
static void
 
233
places_view_button_update(PlacesData *pd)
 
234
{
 
235
    GdkPixbuf *icon;
 
236
    guint size;
 
237
    
 
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);
 
241
 
 
242
    icon = xfce_themed_icon_load_category(2, size);
 
243
    if(G_LIKELY(icon != NULL)){
 
244
 
 
245
        gtk_image_set_from_pixbuf(GTK_IMAGE(pd->view_button_image), icon);
 
246
        g_object_unref(G_OBJECT(icon));
 
247
 
 
248
    }else{
 
249
        // I'd use this, but it's new in gtk 2.8:
 
250
        // gtk_image_clear(GTK_IMAGE(pd->view_button_image));
 
251
 
 
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);
 
256
 
 
257
    }
 
258
}
 
259
 
 
260
/********** Gtk Callbacks **********/
 
261
 
 
262
// Panel callbacks
 
263
 
 
264
static gboolean
 
265
places_view_cb_size_changed(PlacesData *pd, guint size)
 
266
{
 
267
    gtk_widget_set_size_request(pd->view_button, size, size);
 
268
 
 
269
    if(GTK_WIDGET_REALIZED(pd->view_button))
 
270
        places_view_button_update(pd);
 
271
 
 
272
    return TRUE;
 
273
}
 
274
 
 
275
static gboolean
 
276
places_view_cb_theme_changed(GSignalInvocationHint *ihint,
 
277
                             guint n_param_values, const GValue *param_values,
 
278
                             PlacesData *pd)
 
279
{
 
280
    // update the button
 
281
    if(GTK_WIDGET_REALIZED(pd->view_button))
 
282
        places_view_button_update(pd);
 
283
    
 
284
    // force a menu update
 
285
    places_view_destroy_menu(pd);
 
286
 
 
287
    return TRUE;
 
288
}
 
289
 
 
290
// Menu callbacks
 
291
 
 
292
/* Copied almost verbatim from xfdesktop plugin */
 
293
static void
 
294
places_view_cb_menu_position(GtkMenu *menu, 
 
295
                             gint *x, gint *y, 
 
296
                             gboolean *push_in, 
 
297
                             PlacesData *pd)
 
298
{
 
299
    XfceScreenPosition pos;
 
300
    GtkRequisition req;
 
301
 
 
302
    gtk_widget_size_request(GTK_WIDGET(menu), &req);
 
303
 
 
304
    gdk_window_get_origin (GTK_WIDGET (pd->plugin)->window, x, y);
 
305
 
 
306
    pos = xfce_panel_plugin_get_screen_position(pd->plugin);
 
307
 
 
308
    switch(pos) {
 
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;
 
314
            break;
 
315
        
 
316
        case XFCE_SCREEN_POSITION_NE_V:
 
317
        case XFCE_SCREEN_POSITION_E:
 
318
        case XFCE_SCREEN_POSITION_SE_V:
 
319
            *x -= req.width;
 
320
            *y += pd->view_button->allocation.height - req.height;
 
321
            break;
 
322
        
 
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;
 
327
            break;
 
328
        
 
329
        case XFCE_SCREEN_POSITION_SW_H:
 
330
        case XFCE_SCREEN_POSITION_S:
 
331
        case XFCE_SCREEN_POSITION_SE_H:
 
332
            *y -= req.height;
 
333
            break;
 
334
        
 
335
        default:  /* floating */
 
336
        {
 
337
            GdkScreen *screen = NULL;
 
338
            gint screen_width, screen_height;
 
339
 
 
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)
 
345
                *x -= req.width;
 
346
            if ((*y + req.height) > screen_height)
 
347
                *y -= req.height;
 
348
        }
 
349
    }
 
350
 
 
351
    if (*x < 0)
 
352
        *x = 0;
 
353
 
 
354
    if (*y < 0)
 
355
        *y = 0;
 
356
 
 
357
    /* "wtf is this ?" -Xfdesktop source */
 
358
    *push_in = FALSE;
 
359
}
 
360
 
 
361
static void 
 
362
places_view_cb_menu_deact(PlacesData *pd, GtkWidget *menu)
 
363
{
 
364
    // deactivate button
 
365
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->view_button), FALSE);
 
366
}
 
367
 
 
368
static void
 
369
places_view_cb_menu_item_open(GtkWidget *widget, const gchar* uri)
 
370
{
 
371
    places_load_thunar(uri);
 
372
}
 
373
 
 
374
// Button
 
375
static gboolean
 
376
places_view_cb_button_pressed(PlacesData *pd, GdkEventButton *evt)
 
377
{
 
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))))
 
381
        return FALSE;
 
382
    
 
383
    places_view_open_menu(pd);
 
384
 
 
385
    return FALSE;
 
386
}
 
387
 
 
388
// Recent Documents
 
389
 
 
390
#if USE_RECENT_DOCUMENTS
 
391
static void
 
392
places_view_cb_recent_item_open(GtkRecentChooser *chooser, PlacesData *pd)
 
393
{
 
394
    gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
 
395
    places_load_thunar(uri);
 
396
    g_free(uri);
 
397
}
 
398
 
 
399
static void
 
400
places_view_cb_recent_items_clear(GtkWidget *clear_item)
 
401
{
 
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);
 
405
}
 
406
#endif
 
407
 
 
408
/********** Model Visitor Callbacks **********/
 
409
 
 
410
static void
 
411
places_view_add_menu_item(gpointer _pd, const gchar *label, const gchar *uri, const gchar *icon)
 
412
{
 
413
    g_assert(_pd != NULL);
 
414
    g_return_if_fail(label != NULL && label != "");
 
415
    g_return_if_fail(uri != NULL && uri != "");
 
416
 
 
417
    PlacesData *pd = (PlacesData*) _pd;
 
418
    GtkWidget *item = gtk_image_menu_item_new_with_label(label);
 
419
 
 
420
    if(G_LIKELY(icon != NULL)){
 
421
        GdkPixbuf *pb = xfce_themed_icon_load(icon, 16);
 
422
        
 
423
        if(G_LIKELY(pb != NULL)){
 
424
            GtkWidget *image = gtk_image_new_from_pixbuf(pb);
 
425
            g_object_unref(pb);
 
426
            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
 
427
        }
 
428
    }
 
429
 
 
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);
 
433
}
 
434
 
 
435
static void
 
436
places_view_add_menu_sep(gpointer _pd)
 
437
{
 
438
    g_assert(_pd != NULL);
 
439
    PlacesData *pd = (PlacesData*) _pd;
 
440
 
 
441
    gtk_menu_shell_append(GTK_MENU_SHELL(pd->view_menu),
 
442
                          gtk_separator_menu_item_new());
 
443
}
 
444
 
 
445
// vim: ai et tabstop=4