~ubuntu-branches/ubuntu/hardy/pcmanfm/hardy-backports

« back to all changes in this revision

Viewing changes to src/desktop/desktop-window.c

  • Committer: Bazaar Package Importer
  • Author(s): J?r?me Guelfucci
  • Date: 2008-07-01 00:40:37 UTC
  • mfrom: (5.1.3 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080701004037-q6pfacskp0xnk10k
Tags: 0.4.3-1~hardy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      desktop-window.c
 
3
 *
 
4
 *      Copyright 2008 PCMan <pcman.tw@gmail.com>
 
5
 *
 
6
 *      This program is free software; you can redistribute it and/or modify
 
7
 *      it under the terms of the GNU General Public License as published by
 
8
 *      the Free Software Foundation; either version 2 of the License, or
 
9
 *      (at your option) any later version.
 
10
 *
 
11
 *      This program is distributed in the hope that it will be useful,
 
12
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *      GNU General Public License for more details.
 
15
 *
 
16
 *      You should have received a copy of the GNU General Public License
 
17
 *      along with this program; if not, write to the Free Software
 
18
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
19
 *      MA 02110-1301, USA.
 
20
 */
 
21
 
 
22
#include <glib/gi18n.h>
 
23
 
 
24
#include "desktop-window.h"
 
25
#include "vfs-file-info.h"
 
26
#include "vfs-mime-type.h"
 
27
 
 
28
#include "glib-mem.h"
 
29
#include "working-area.h"
 
30
 
 
31
#include "ptk-file-misc.h"
 
32
#include "ptk-file-menu.h"
 
33
#include "ptk-file-task.h"
 
34
#include "ptk-utils.h"
 
35
 
 
36
#include "settings.h"
 
37
#include "main-window.h"
 
38
#include "pref-dialog.h"
 
39
#include "ptk-file-browser.h"
 
40
 
 
41
#include <X11/Xlib.h>
 
42
#include <X11/Xatom.h>
 
43
#include <gdk/gdkx.h>
 
44
#include <gdk/gdkkeysyms.h>
 
45
 
 
46
/* for stat */
 
47
#include <sys/types.h>
 
48
#include <sys/stat.h>
 
49
#include <unistd.h>
 
50
 
 
51
struct _DesktopItem
 
52
{
 
53
    VFSFileInfo* fi;
 
54
    guint order;
 
55
    GdkRectangle box;   /* bounding rect */
 
56
    GdkRectangle icon_rect;
 
57
    GdkRectangle text_rect;
 
58
 
 
59
    /* Since pango doesn't support using "wrap" and "ellipsize" at the same time,
 
60
         let's  do some dirty hack here.  We draw these two lines separately, and
 
61
         we can ellipsize the second line. */
 
62
    int len1;   /* length for the first line of label text */
 
63
    int line_h1;    /* height of the first line */
 
64
 
 
65
    gboolean is_selected : 1;
 
66
    gboolean is_prelight : 1;
 
67
};
 
68
 
 
69
static void desktop_window_class_init           (DesktopWindowClass *klass);
 
70
static void desktop_window_init             (DesktopWindow *self);
 
71
static void desktop_window_finalize         (GObject *object);
 
72
 
 
73
static gboolean on_expose( GtkWidget* w, GdkEventExpose* evt );
 
74
static void on_size_allocate( GtkWidget* w, GtkAllocation* alloc );
 
75
static void on_size_request( GtkWidget* w, GtkRequisition* req );
 
76
static gboolean on_button_press( GtkWidget* w, GdkEventButton* evt );
 
77
static gboolean on_button_release( GtkWidget* w, GdkEventButton* evt );
 
78
static gboolean on_mouse_move( GtkWidget* w, GdkEventMotion* evt );
 
79
static gboolean on_key_press( GtkWidget* w, GdkEventKey* evt );
 
80
static void on_style_set( GtkWidget* w, GtkStyle* prev );
 
81
static void on_realize( GtkWidget* w );
 
82
static gboolean on_focus_in( GtkWidget* w, GdkEventFocus* evt );
 
83
static gboolean on_focus_out( GtkWidget* w, GdkEventFocus* evt );
 
84
/* static gboolean on_scroll( GtkWidget *w, GdkEventScroll *evt, gpointer user_data ); */
 
85
 
 
86
static void on_drag_begin( GtkWidget* w, GdkDragContext* ctx );
 
87
static gboolean on_drag_motion( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time );
 
88
static gboolean on_drag_drop( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time );
 
89
static void on_drag_data_get( GtkWidget* w, GdkDragContext* ctx, GtkSelectionData* data, guint info, guint time );
 
90
static void on_drag_data_received( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, GtkSelectionData* data, guint info, guint time );
 
91
static void on_drag_leave( GtkWidget* w, GdkDragContext* ctx, guint time );
 
92
static void on_drag_end( GtkWidget* w, GdkDragContext* ctx );
 
93
 
 
94
static void on_file_listed( VFSDir* dir,  gboolean is_cancelled, DesktopWindow* self );
 
95
static void on_file_created( VFSDir* dir, VFSFileInfo* file, gpointer user_data );
 
96
static void on_file_deleted( VFSDir* dir, VFSFileInfo* file, gpointer user_data );
 
97
static void on_file_changed( VFSDir* dir, VFSFileInfo* file, gpointer user_data );
 
98
static void on_thumbnail_loaded( VFSDir* dir,  VFSFileInfo* fi, DesktopWindow* self );
 
99
 
 
100
static void on_sort_by_name ( GtkMenuItem *menuitem, DesktopWindow* self );
 
101
static void on_sort_by_size ( GtkMenuItem *menuitem, DesktopWindow* self );
 
102
static void on_sort_by_mtime ( GtkMenuItem *menuitem, DesktopWindow* self );
 
103
static void on_sort_by_type ( GtkMenuItem *menuitem, DesktopWindow* self );
 
104
static void on_sort_custom( GtkMenuItem *menuitem, DesktopWindow* self );
 
105
static void on_sort_ascending( GtkMenuItem *menuitem, DesktopWindow* self );
 
106
static void on_sort_descending( GtkMenuItem *menuitem, DesktopWindow* self );
 
107
 
 
108
static void on_paste( GtkMenuItem *menuitem, DesktopWindow* self );
 
109
static void on_settings( GtkMenuItem *menuitem, DesktopWindow* self );
 
110
 
 
111
static void on_popup_new_folder_activate ( GtkMenuItem *menuitem, gpointer data );
 
112
static void on_popup_new_text_file_activate ( GtkMenuItem *menuitem, gpointer data );
 
113
 
 
114
static GdkFilterReturn on_rootwin_event ( GdkXEvent *xevent, GdkEvent *event, gpointer data );
 
115
static void forward_event_to_rootwin( GdkScreen *gscreen, GdkEvent *event );
 
116
 
 
117
static void calc_item_size( DesktopWindow* self, DesktopItem* item );
 
118
static void layout_items( DesktopWindow* self );
 
119
static void paint_item( DesktopWindow* self, DesktopItem* item, GdkRectangle* expose_area );
 
120
static void move_item( DesktopWindow* self, DesktopItem* item, int x, int y, gboolean is_offset );
 
121
static void paint_rubber_banding_rect( DesktopWindow* self );
 
122
 
 
123
/* FIXME: this is too dirty and here is some redundant code.
 
124
 *  We really need better and cleaner APIs for this */
 
125
static void open_folders( GList* folders );
 
126
 
 
127
static GList* sort_items( GList* items, DesktopWindow* win );
 
128
static GCompareDataFunc get_sort_func( DesktopWindow* win );
 
129
static int comp_item_by_name( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win );
 
130
static int comp_item_by_size( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win );
 
131
static int comp_item_by_mtime( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win );
 
132
static int comp_item_by_type( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win );
 
133
static int comp_item_custom( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win );
 
134
 
 
135
static void redraw_item( DesktopWindow* win, DesktopItem* item );
 
136
static void desktop_item_free( DesktopItem* item );
 
137
 
 
138
/*
 
139
static GdkPixmap* get_root_pixmap( GdkWindow* root );
 
140
static gboolean set_root_pixmap(  GdkWindow* root , GdkPixmap* pix );
 
141
*/
 
142
 
 
143
static DesktopItem* hit_test( DesktopWindow* self, int x, int y );
 
144
 
 
145
/* static Atom ATOM_XROOTMAP_ID = 0; */
 
146
static Atom ATOM_NET_WORKAREA = 0;
 
147
 
 
148
/* Local data */
 
149
static GtkWindowClass *parent_class = NULL;
 
150
 
 
151
static GdkPixmap* pix = NULL;
 
152
 
 
153
enum {
 
154
    DRAG_TARGET_URI_LIST,
 
155
    DRAG_TARGET_DESKTOP_ICON
 
156
};
 
157
 
 
158
/*  Drag & Drop/Clipboard targets  */
 
159
static GtkTargetEntry drag_targets[] = {
 
160
   { "text/uri-list", 0 , DRAG_TARGET_URI_LIST },
 
161
   { "DESKTOP_ICON", GTK_TARGET_SAME_WIDGET, DRAG_TARGET_DESKTOP_ICON }
 
162
};
 
163
 
 
164
static GdkAtom text_uri_list_atom = 0;
 
165
static GdkAtom desktop_icon_atom = 0;
 
166
 
 
167
static PtkMenuItemEntry icon_menu[] =
 
168
{
 
169
    PTK_RADIO_MENU_ITEM( N_( "Sort by _Name" ), on_sort_by_name, 0, 0 ),
 
170
    PTK_RADIO_MENU_ITEM( N_( "Sort by _Size" ), on_sort_by_size, 0, 0 ),
 
171
    PTK_RADIO_MENU_ITEM( N_( "Sort by _Type" ), on_sort_by_type, 0, 0 ),
 
172
    PTK_RADIO_MENU_ITEM( N_( "Sort by _Modification Time" ), on_sort_by_mtime, 0, 0 ),
 
173
    /* PTK_RADIO_MENU_ITEM( N_( "Custom" ), on_sort_custom, 0, 0 ), */
 
174
    PTK_SEPARATOR_MENU_ITEM,
 
175
    PTK_RADIO_MENU_ITEM( N_( "Ascending" ), on_sort_ascending, 0, 0 ),
 
176
    PTK_RADIO_MENU_ITEM( N_( "Descending" ), on_sort_descending, 0, 0 ),
 
177
    PTK_MENU_END
 
178
};
 
179
 
 
180
static PtkMenuItemEntry create_new_menu[] =
 
181
{
 
182
    PTK_IMG_MENU_ITEM( N_( "_Folder" ), "gtk-directory", on_popup_new_folder_activate, 0, 0 ),
 
183
    PTK_IMG_MENU_ITEM( N_( "_Text File" ), "gtk-edit", on_popup_new_text_file_activate, 0, 0 ),
 
184
    PTK_MENU_END
 
185
};
 
186
 
 
187
static PtkMenuItemEntry desktop_menu[] =
 
188
{
 
189
    PTK_POPUP_MENU( N_( "_Icons" ), icon_menu ),
 
190
    PTK_STOCK_MENU_ITEM( GTK_STOCK_PASTE, on_paste ),
 
191
    PTK_SEPARATOR_MENU_ITEM,
 
192
    PTK_POPUP_IMG_MENU( N_( "_Create New" ), "gtk-new", create_new_menu ),
 
193
    PTK_SEPARATOR_MENU_ITEM,
 
194
    PTK_IMG_MENU_ITEM( N_( "_Desktop Settings" ), GTK_STOCK_PREFERENCES, on_settings, GDK_Return, GDK_MOD1_MASK ),
 
195
    PTK_MENU_END
 
196
};
 
197
 
 
198
GType desktop_window_get_type(void)
 
199
{
 
200
    static GType self_type = 0;
 
201
    if (! self_type)
 
202
    {
 
203
        static const GTypeInfo self_info =
 
204
        {
 
205
            sizeof(DesktopWindowClass),
 
206
            NULL, /* base_init */
 
207
            NULL, /* base_finalize */
 
208
            (GClassInitFunc)desktop_window_class_init,
 
209
            NULL, /* class_finalize */
 
210
            NULL, /* class_data */
 
211
            sizeof(DesktopWindow),
 
212
            0,
 
213
            (GInstanceInitFunc)desktop_window_init,
 
214
            NULL /* value_table */
 
215
        };
 
216
 
 
217
        self_type = g_type_register_static(GTK_TYPE_WINDOW, "DesktopWindow", &self_info, 0);    }
 
218
 
 
219
    return self_type;
 
220
}
 
221
 
 
222
static void desktop_window_class_init(DesktopWindowClass *klass)
 
223
{
 
224
    GObjectClass *g_object_class;
 
225
    GtkWidgetClass* wc;
 
226
        typedef gboolean (*DeleteEvtHandler) (GtkWidget*, GdkEvent*);
 
227
 
 
228
    g_object_class = G_OBJECT_CLASS(klass);
 
229
    wc = GTK_WIDGET_CLASS(klass);
 
230
 
 
231
    g_object_class->finalize = desktop_window_finalize;
 
232
 
 
233
    wc->expose_event = on_expose;
 
234
    wc->size_allocate = on_size_allocate;
 
235
    wc->size_request = on_size_request;
 
236
    wc->button_press_event = on_button_press;
 
237
    wc->button_release_event = on_button_release;
 
238
    wc->motion_notify_event = on_mouse_move;
 
239
    wc->key_press_event = on_key_press;
 
240
    wc->style_set = on_style_set;
 
241
    wc->realize = on_realize;
 
242
    wc->focus_in_event = on_focus_in;
 
243
    wc->focus_out_event = on_focus_out;
 
244
    /* wc->scroll_event = on_scroll; */
 
245
    wc->delete_event = (DeleteEvtHandler) gtk_true;
 
246
 
 
247
    wc->drag_begin = on_drag_begin;
 
248
    wc->drag_motion = on_drag_motion;
 
249
    wc->drag_drop = on_drag_drop;
 
250
    wc->drag_data_get = on_drag_data_get;
 
251
    wc->drag_data_received = on_drag_data_received;
 
252
    wc->drag_leave = on_drag_leave;
 
253
    wc->drag_end = on_drag_end;
 
254
 
 
255
    parent_class = (GtkWindowClass*)g_type_class_peek(GTK_TYPE_WINDOW);
 
256
 
 
257
    /* ATOM_XROOTMAP_ID = XInternAtom( GDK_DISPLAY(),"_XROOTMAP_ID", False ); */
 
258
    ATOM_NET_WORKAREA = XInternAtom( GDK_DISPLAY(),"_NET_WORKAREA", False );
 
259
 
 
260
    text_uri_list_atom = gdk_atom_intern_static_string( drag_targets[DRAG_TARGET_URI_LIST].target );
 
261
    desktop_icon_atom = gdk_atom_intern_static_string( drag_targets[DRAG_TARGET_DESKTOP_ICON].target );
 
262
}
 
263
 
 
264
static void desktop_window_init(DesktopWindow *self)
 
265
{
 
266
    PangoContext* pc;
 
267
    PangoFontMetrics *metrics;
 
268
    int font_h;
 
269
    GdkWindow* root;
 
270
 
 
271
    /* sort by name by default */
 
272
//    self->sort_by = DW_SORT_BY_NAME;
 
273
//    self->sort_type = GTK_SORT_ASCENDING;
 
274
    self->sort_by = app_settings.desktop_sort_by;
 
275
    self->sort_type = app_settings.desktop_sort_type;
 
276
 
 
277
    self->icon_render = gtk_cell_renderer_pixbuf_new();
 
278
    g_object_set( self->icon_render, "follow-state", TRUE, NULL);
 
279
#if GTK_CHECK_VERSION( 2, 10, 0 )
 
280
    g_object_ref_sink(self->icon_render);
 
281
#else
 
282
    g_object_ref( self->icon_render );
 
283
    gtk_object_sink(self->icon_render);
 
284
#endif
 
285
    pc = gtk_widget_get_pango_context( (GtkWidget*)self );
 
286
    self->pl = gtk_widget_create_pango_layout( (GtkWidget*)self, NULL );
 
287
    pango_layout_set_alignment( self->pl, PANGO_ALIGN_CENTER );
 
288
    pango_layout_set_wrap( self->pl, PANGO_WRAP_WORD_CHAR );
 
289
    pango_layout_set_width( self->pl, 100 * PANGO_SCALE );
 
290
 
 
291
    metrics = pango_context_get_metrics(
 
292
                            pc, ((GtkWidget*)self)->style->font_desc,
 
293
                            pango_context_get_language(pc));
 
294
 
 
295
    font_h = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent (metrics);
 
296
    font_h /= PANGO_SCALE;
 
297
 
 
298
    self->label_w = 100;
 
299
    self->icon_size = 48;
 
300
    self->spacing = 1;
 
301
    self->x_pad = 6;
 
302
    self->y_pad = 6;
 
303
    self->y_margin = 6;
 
304
    self->x_margin = 6;
 
305
 
 
306
    self->dir = vfs_dir_get_by_path( vfs_get_desktop_dir() );
 
307
    if( vfs_dir_is_file_listed( self->dir ) )
 
308
        on_file_listed( self->dir, FALSE, self );
 
309
    g_signal_connect( self->dir, "file-listed", G_CALLBACK( on_file_listed ), self );
 
310
    g_signal_connect( self->dir, "file-created", G_CALLBACK( on_file_created ), self );
 
311
    g_signal_connect( self->dir, "file-deleted", G_CALLBACK( on_file_deleted ), self );
 
312
    g_signal_connect( self->dir, "file-changed", G_CALLBACK( on_file_changed ), self );
 
313
    g_signal_connect( self->dir, "thumbnail-loaded", G_CALLBACK( on_thumbnail_loaded ), self );
 
314
 
 
315
    GTK_WIDGET_SET_FLAGS( (GtkWidget*)self, GTK_CAN_FOCUS );
 
316
 
 
317
    gtk_widget_set_app_paintable(  (GtkWidget*)self, TRUE );
 
318
/*    gtk_widget_set_double_buffered(  (GtkWidget*)self, FALSE ); */
 
319
    gtk_widget_add_events( (GtkWidget*)self,
 
320
                                            GDK_POINTER_MOTION_MASK |
 
321
                                            GDK_BUTTON_PRESS_MASK |
 
322
                                            GDK_BUTTON_RELEASE_MASK |
 
323
                                            GDK_KEY_PRESS_MASK|
 
324
                                            GDK_PROPERTY_CHANGE_MASK );
 
325
 
 
326
    gtk_drag_dest_set( (GtkWidget*)self, 0, NULL, 0,
 
327
                       GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK );
 
328
 
 
329
    root = gdk_screen_get_root_window( gtk_widget_get_screen( (GtkWidget*)self ) );
 
330
    gdk_window_set_events( root, gdk_window_get_events( root )
 
331
                           | GDK_PROPERTY_CHANGE_MASK );
 
332
    gdk_window_add_filter( root, on_rootwin_event, self );
 
333
}
 
334
 
 
335
 
 
336
GtkWidget* desktop_window_new(void)
 
337
{
 
338
    GtkWindow* w = (GtkWindow*)g_object_new(DESKTOP_WINDOW_TYPE, NULL);
 
339
    w->type = GTK_WINDOW_TOPLEVEL;
 
340
    return (GtkWidget*)w;
 
341
}
 
342
 
 
343
void desktop_item_free( DesktopItem* item )
 
344
{
 
345
        vfs_file_info_unref( item->fi );
 
346
        g_slice_free( DesktopItem, item );
 
347
}
 
348
 
 
349
void desktop_window_finalize(GObject *object)
 
350
{
 
351
    DesktopWindow *self = (DesktopWindow*)object;
 
352
 
 
353
    g_return_if_fail(object != NULL);
 
354
    g_return_if_fail(IS_DESKTOP_WINDOW(object));
 
355
 
 
356
    gdk_window_remove_filter(
 
357
                    gdk_screen_get_root_window( gtk_widget_get_screen( (GtkWidget*)object) ),
 
358
                    on_rootwin_event, self );
 
359
 
 
360
    if( self->background )
 
361
        g_object_unref( self->background );
 
362
 
 
363
    self = DESKTOP_WINDOW(object);
 
364
    g_object_unref( self->dir );
 
365
 
 
366
        g_list_foreach( self->items, (GFunc)desktop_item_free, NULL );
 
367
        g_list_free( self->items );
 
368
 
 
369
    if (G_OBJECT_CLASS(parent_class)->finalize)
 
370
        (* G_OBJECT_CLASS(parent_class)->finalize)(object);
 
371
}
 
372
 
 
373
/*--------------- Signal handlers --------------*/
 
374
 
 
375
gboolean on_expose( GtkWidget* w, GdkEventExpose* evt )
 
376
{
 
377
    DesktopWindow* self = (DesktopWindow*)w;
 
378
    GList* l;
 
379
    GdkRectangle intersect;
 
380
 
 
381
    if( G_UNLIKELY( ! GTK_WIDGET_VISIBLE (w) || ! GTK_WIDGET_MAPPED (w) ) )
 
382
        return TRUE;
 
383
/*
 
384
    gdk_draw_drawable( w->window, self->gc,
 
385
                        self->background,
 
386
                        evt->area.x, evt->area.y,
 
387
                        evt->area.x, evt->area.y,
 
388
                        evt->area.width, evt->area.height );
 
389
*/
 
390
/*
 
391
    gdk_gc_set_tile( self->gc, self->background );
 
392
    gdk_gc_set_fill( self->gc,  GDK_TILED );/*
 
393
    gdk_draw_rectangle( w->window, self->gc, TRUE,
 
394
                        evt->area.x, evt->area.y,
 
395
                        evt->area.width, evt->area.height );
 
396
*/
 
397
 
 
398
    if( self->rubber_bending )
 
399
        paint_rubber_banding_rect( self );
 
400
 
 
401
    for( l = self->items; l; l = l->next )
 
402
    {
 
403
        DesktopItem* item = (DesktopItem*)l->data;
 
404
        if( gdk_rectangle_intersect( &evt->area, &item->box, &intersect ) )
 
405
            paint_item( self, item, &intersect );
 
406
    }
 
407
    return TRUE;
 
408
}
 
409
 
 
410
void on_size_allocate( GtkWidget* w, GtkAllocation* alloc )
 
411
{
 
412
    GdkPixbuf* pix;
 
413
    DesktopWindow* self = (DesktopWindow*)w;
 
414
    GdkRectangle wa;
 
415
 
 
416
    get_working_area( gtk_widget_get_screen(w), &self->wa );
 
417
    layout_items( w );
 
418
 
 
419
    GTK_WIDGET_CLASS(parent_class)->size_allocate( w, alloc );
 
420
}
 
421
 
 
422
void desktop_window_set_pixmap( DesktopWindow* win, GdkPixmap* pix )
 
423
{
 
424
    if( win->background )
 
425
        g_object_unref( win->background );
 
426
    win->background = pix ? g_object_ref( pix ) : NULL;
 
427
 
 
428
    if( GTK_WIDGET_REALIZED( win ) )
 
429
        gdk_window_set_back_pixmap( ((GtkWidget*)win)->window, win->background, FALSE );
 
430
}
 
431
 
 
432
void desktop_window_set_bg_color( DesktopWindow* win, GdkColor* clr )
 
433
{
 
434
    if( clr )
 
435
    {
 
436
        win->bg = *clr;
 
437
        gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
 
438
                            &win->bg );
 
439
        if( GTK_WIDGET_VISIBLE(win) )
 
440
            gtk_widget_queue_draw(  (GtkWidget*)win );
 
441
    }
 
442
}
 
443
 
 
444
void desktop_window_set_text_color( DesktopWindow* win, GdkColor* clr, GdkColor* shadow )
 
445
{
 
446
    if( clr || shadow )
 
447
    {
 
448
        if( clr )
 
449
        {
 
450
            win->fg = *clr;
 
451
            gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
 
452
                                &win->fg );
 
453
        }
 
454
        if( shadow )
 
455
        {
 
456
            win->shadow = *shadow;
 
457
            gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
 
458
                                &win->shadow );
 
459
        }
 
460
        if( GTK_WIDGET_VISIBLE(win) )
 
461
            gtk_widget_queue_draw(  (GtkWidget*)win );
 
462
    }
 
463
}
 
464
 
 
465
/*
 
466
 *  Set background of the desktop window.
 
467
 *  src_pix is the source pixbuf in original size (no scaling)
 
468
 *  This function will stretch or add border to this pixbuf accordiong to 'type'.
 
469
 *  If type = DW_BG_COLOR and src_pix = NULL, the background color is used to fill the window.
 
470
 */
 
471
void desktop_window_set_background( DesktopWindow* win, GdkPixbuf* src_pix, DWBgType type )
 
472
{
 
473
    GdkPixmap* pixmap = NULL;
 
474
    Display* xdisplay;
 
475
    Pixmap xpixmap = 0;
 
476
    Window xroot;
 
477
 
 
478
    win->bg_type = type;
 
479
 
 
480
    if( src_pix )
 
481
    {
 
482
        int src_w = gdk_pixbuf_get_width(src_pix);
 
483
        int src_h = gdk_pixbuf_get_height(src_pix);
 
484
        int dest_w = gdk_screen_get_width( gtk_widget_get_screen((GtkWidget*)win) );
 
485
        int dest_h = gdk_screen_get_height( gtk_widget_get_screen((GtkWidget*)win) );
 
486
        GdkPixbuf* scaled = NULL;
 
487
 
 
488
        if( type == DW_BG_TILE )
 
489
        {
 
490
            pixmap = gdk_pixmap_new( ((GtkWidget*)win)->window, src_w, src_h, -1 );
 
491
            gdk_draw_pixbuf( pixmap, NULL, src_pix, 0, 0, 0, 0, src_w, src_h, GDK_RGB_DITHER_NORMAL, 0, 0 );
 
492
        }
 
493
        else
 
494
        {
 
495
            int src_x = 0, src_y = 0;
 
496
            int dest_x = 0, dest_y = 0;
 
497
            int w = 0, h = 0;
 
498
 
 
499
            pixmap = gdk_pixmap_new( ((GtkWidget*)win)->window, dest_w, dest_h, -1 );
 
500
            switch( type )
 
501
            {
 
502
            case DW_BG_STRETCH:
 
503
                if( src_w == dest_w && src_h == dest_h ) /* the same size, no scale is needed */
 
504
                    scaled = (GdkPixbuf*)g_object_ref( src_pix );
 
505
                else
 
506
                    scaled = gdk_pixbuf_scale_simple( src_pix, dest_w, dest_h, GDK_INTERP_BILINEAR );
 
507
                w = dest_w;
 
508
                h = dest_h;
 
509
                break;
 
510
            case DW_BG_FULL:
 
511
                if( src_w == dest_w && src_h == dest_h )
 
512
                    scaled = (GdkPixbuf*)g_object_ref( src_pix );
 
513
                else
 
514
                {
 
515
                    gdouble w_ratio = (float)dest_w / src_w;
 
516
                    gdouble h_ratio = (float)dest_h / src_h;
 
517
                    gdouble ratio = MIN( w_ratio, h_ratio );
 
518
                    if( ratio == 1.0 )
 
519
                        scaled = (GdkPixbuf*)g_object_ref( src_pix );
 
520
                    else
 
521
                        scaled = gdk_pixbuf_scale_simple( src_pix, (src_w * ratio), (src_h * ratio), GDK_INTERP_BILINEAR );
 
522
                }
 
523
                w = gdk_pixbuf_get_width( scaled );
 
524
                h = gdk_pixbuf_get_height( scaled );
 
525
 
 
526
                if( w > dest_w )
 
527
                    src_x = (w - dest_w) / 2;
 
528
                else if( w < dest_w )
 
529
                    dest_x = (dest_w - w) / 2;
 
530
 
 
531
                if( h > dest_h )
 
532
                    src_y = (h - dest_h) / 2;
 
533
                else if( h < dest_h )
 
534
                    dest_y = (dest_h - h) / 2;
 
535
                break;
 
536
            case DW_BG_CENTER:  /* no scale is needed */
 
537
                scaled = (GdkPixbuf*)g_object_ref( src_pix );
 
538
 
 
539
                if( src_w > dest_w )
 
540
                {
 
541
                    w = dest_w;
 
542
                    src_x = (src_w - dest_w) / 2;
 
543
                }
 
544
                else
 
545
                {
 
546
                    w = src_w;
 
547
                    dest_x = (dest_w - src_w) / 2;
 
548
                }
 
549
                if( src_h > dest_h )
 
550
                {
 
551
                    h = dest_h;
 
552
                    src_y = (src_h - dest_h) / 2;
 
553
                }
 
554
                else
 
555
                {
 
556
                    h = src_h;
 
557
                    dest_y = (dest_h - src_h) / 2;
 
558
                }
 
559
                break;
 
560
            }
 
561
 
 
562
            if( scaled )
 
563
            {
 
564
                if( w != dest_w || h != dest_h )
 
565
                {
 
566
                    GdkGC *gc = gdk_gc_new( ((GtkWidget*)win)->window );
 
567
                    gdk_gc_set_fill(gc, GDK_SOLID);
 
568
                    gdk_gc_set_foreground( gc, &win->bg);
 
569
                    gdk_draw_rectangle( pixmap, gc, TRUE, 0, 0, dest_w, dest_h );
 
570
                    g_object_unref(gc);
 
571
                }
 
572
                gdk_draw_pixbuf( pixmap, NULL, scaled, src_x, src_y, dest_x, dest_y, w, h,
 
573
                                                GDK_RGB_DITHER_NORMAL, 0, 0 );
 
574
                g_object_unref( scaled );
 
575
            }
 
576
            else
 
577
            {
 
578
                g_object_unref( pixmap );
 
579
                pixmap = NULL;
 
580
            }
 
581
        }
 
582
    }
 
583
 
 
584
    if( win->background )
 
585
        g_object_unref( win->background );
 
586
    win->background = pixmap;
 
587
 
 
588
    if( pixmap )
 
589
        gdk_window_set_back_pixmap( ((GtkWidget*)win)->window, pixmap, FALSE );
 
590
    else
 
591
        gdk_window_set_background( ((GtkWidget*)win)->window, &win->bg );
 
592
 
 
593
    gdk_window_clear( ((GtkWidget*)win)->window );
 
594
    gtk_widget_queue_draw( (GtkWidget*)win );
 
595
 
 
596
    /* set root map here */
 
597
    xdisplay = GDK_DISPLAY_XDISPLAY( gtk_widget_get_display( (GtkWidget*)win) );
 
598
    xroot = GDK_WINDOW_XID( gtk_widget_get_root_window( (GtkWidget*)win ) );
 
599
 
 
600
    XGrabServer (xdisplay);
 
601
 
 
602
    if( pixmap )
 
603
    {
 
604
        xpixmap = GDK_WINDOW_XWINDOW(pixmap);
 
605
 
 
606
        XChangeProperty( xdisplay,
 
607
                    xroot,
 
608
                    gdk_x11_get_xatom_by_name("_XROOTPMAP_ID"), XA_PIXMAP,
 
609
                    32, PropModeReplace,
 
610
                    (guchar *) &xpixmap, 1);
 
611
 
 
612
        XSetWindowBackgroundPixmap( xdisplay, xroot, xpixmap );
 
613
    }
 
614
    else
 
615
    {
 
616
        /* FIXME: Anyone knows how to handle this correctly??? */
 
617
    }
 
618
    XClearWindow( xdisplay, xroot );
 
619
 
 
620
    XUngrabServer( xdisplay );
 
621
    XFlush( xdisplay );
 
622
}
 
623
 
 
624
void desktop_window_set_icon_size( DesktopWindow* win, int size )
 
625
{
 
626
    GList* l;
 
627
    win->icon_size = size;
 
628
    layout_items( win );
 
629
    for( l = win->items; l; l = l->next )
 
630
    {
 
631
        VFSFileInfo* fi = ((DesktopItem*)l->data)->fi;
 
632
        char* path;
 
633
        /* reload the icons for special items if needed */
 
634
        if( (fi->flags & VFS_FILE_INFO_DESKTOP_ENTRY)  && ! fi->big_thumbnail)
 
635
        {
 
636
            path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
 
637
            vfs_file_info_load_special_info( fi, path );
 
638
            g_free( path );
 
639
        }
 
640
        else if(fi->flags & VFS_FILE_INFO_VIRTUAL)
 
641
        {
 
642
            /* Currently only "My Documents" is supported */
 
643
            if( fi->big_thumbnail )
 
644
                g_object_unref( fi->big_thumbnail );
 
645
            fi->big_thumbnail = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gnome-fs-home", size, 0, NULL );
 
646
            if( ! fi->big_thumbnail )
 
647
                fi->big_thumbnail = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "folder-home", size, 0, NULL );
 
648
        }
 
649
        else if( vfs_file_info_is_image( fi ) && ! fi->big_thumbnail )
 
650
        {
 
651
            vfs_thumbnail_loader_request( win->dir, fi, TRUE );
 
652
        }
 
653
    }
 
654
}
 
655
 
 
656
void desktop_window_reload_icons( DesktopWindow* win )
 
657
{
 
658
/*
 
659
        GList* l;
 
660
        for( l = win->items; l; l = l->next )
 
661
        {
 
662
                DesktopItem* item = (DesktopItem*)l->data;
 
663
 
 
664
                if( item->icon )
 
665
                        g_object_unref( item->icon );
 
666
 
 
667
                if( item->fi )
 
668
                        item->icon =  vfs_file_info_get_big_icon( item->fi );
 
669
                else
 
670
                        item->icon = NULL;
 
671
        }
 
672
*/
 
673
        layout_items( win );
 
674
}
 
675
 
 
676
 
 
677
 
 
678
void on_size_request( GtkWidget* w, GtkRequisition* req )
 
679
{
 
680
    GdkScreen* scr = gtk_widget_get_screen( w );
 
681
    req->width = gdk_screen_get_width( scr );
 
682
    req->height = gdk_screen_get_height( scr );
 
683
}
 
684
 
 
685
static void calc_rubber_banding_rect( DesktopWindow* self, int x, int y, GdkRectangle* rect )
 
686
{
 
687
    int x1, x2, y1, y2, w, h;
 
688
    if( self->drag_start_x < x )
 
689
    {
 
690
        x1 = self->drag_start_x;
 
691
        x2 = x;
 
692
    }
 
693
    else
 
694
    {
 
695
        x1 = x;
 
696
        x2 = self->drag_start_x;
 
697
    }
 
698
 
 
699
    if( self->drag_start_y < y )
 
700
    {
 
701
        y1 = self->drag_start_y;
 
702
        y2 = y;
 
703
    }
 
704
    else
 
705
    {
 
706
        y1 = y;
 
707
        y2 = self->drag_start_y;
 
708
    }
 
709
 
 
710
    rect->x = x1;
 
711
    rect->y = y1;
 
712
    rect->width = x2 - x1;
 
713
    rect->height = y2 - y1;
 
714
}
 
715
 
 
716
/*
 
717
 * Reference: xfdesktop source code
 
718
 * http://svn.xfce.org/index.cgi/xfce/view/xfdesktop/trunk/src/xfdesktop-icon-view.c
 
719
 * xfdesktop_multiply_pixbuf_rgba()
 
720
 * Originally copied from Nautilus, Copyright (C) 2000 Eazel, Inc.
 
721
 * Multiplies each pixel in a pixbuf by the specified color
 
722
 */
 
723
static void colorize_pixbuf( GdkPixbuf* pix, GdkColor* clr, guint alpha )
 
724
{
 
725
    guchar *pixels, *p;
 
726
    int x, y, width, height, rowstride;
 
727
    gboolean has_alpha;
 
728
    int r = clr->red * 255 / 65535;
 
729
    int g = clr->green * 255 / 65535;
 
730
    int b = clr->blue * 255 / 65535;
 
731
    int a = alpha * 255 / 255;
 
732
 
 
733
    pixels = gdk_pixbuf_get_pixels(pix);
 
734
    width = gdk_pixbuf_get_width(pix);
 
735
    height = gdk_pixbuf_get_height(pix);
 
736
    has_alpha = gdk_pixbuf_get_has_alpha(pix);
 
737
    rowstride = gdk_pixbuf_get_rowstride(pix);
 
738
 
 
739
    for (y = 0; y < height; y++)
 
740
    {
 
741
        p = pixels;
 
742
        for (x = 0; x < width; x++)
 
743
        {
 
744
            p[0] = p[0] * r / 255;
 
745
            p[1] = p[1] * g / 255;
 
746
            p[2] = p[2] * b / 255;
 
747
            if( has_alpha )
 
748
            {
 
749
                p[3] = p[3] * a / 255;
 
750
                p += 4;
 
751
            }
 
752
            else
 
753
                p += 3;
 
754
        }
 
755
        pixels += rowstride;
 
756
    }
 
757
}
 
758
 
 
759
void paint_rubber_banding_rect( DesktopWindow* self )
 
760
{
 
761
    int x1, x2, y1, y2, w, h, pattern_w, pattern_h;
 
762
    GdkRectangle rect;
 
763
    GdkColor *clr;
 
764
    guchar alpha;
 
765
    GdkPixbuf* pix;
 
766
    GdkGC* gc;
 
767
 
 
768
    calc_rubber_banding_rect( self, self->rubber_bending_x, self->rubber_bending_y, &rect );
 
769
 
 
770
    if( rect.width <= 0 || rect.height <= 0 )
 
771
        return;
 
772
/*
 
773
    gtk_widget_style_get( GTK_WIDGET(self),
 
774
                        "selection-box-color", &clr,
 
775
                        "selection-box-alpha", &alpha,
 
776
                        NULL);
 
777
*/
 
778
 
 
779
    gc = gdk_gc_new( ((GtkWidget*)self)->window);
 
780
    clr = gdk_color_copy (&GTK_WIDGET (self)->style->base[GTK_STATE_SELECTED]);
 
781
    alpha = 64;  /* FIXME: should be themable in the future */
 
782
 
 
783
    pix = NULL;
 
784
    if( self->bg_type == DW_BG_TILE )
 
785
    {
 
786
        /* FIXME: disable background in tile mode because current implementation is too slow */
 
787
        /*
 
788
        gdk_drawable_get_size( self->background, &pattern_w, &pattern_h );
 
789
        pix = gdk_pixbuf_get_from_drawable( NULL, self->background, gdk_drawable_get_colormap(self->background),
 
790
                                                  0, 0, 0, 0, pattern_w, pattern_h );
 
791
        */
 
792
    }
 
793
    else if( self->bg_type != DW_BG_COLOR )
 
794
    {
 
795
        if( self->background )
 
796
            pix = gdk_pixbuf_get_from_drawable( NULL, self->background, gdk_drawable_get_colormap(self->background),
 
797
                                                rect.x, rect.y, 0, 0, rect.width, rect.height );
 
798
    }
 
799
 
 
800
    if( pix )
 
801
    {
 
802
        colorize_pixbuf( pix, clr, alpha );
 
803
        if( self->bg_type == DW_BG_TILE )
 
804
        {
 
805
            GdkPixmap* pattern;
 
806
            /* FIXME: This is damn slow!! */
 
807
            pattern = gdk_pixmap_new( ((GtkWidget*)self)->window, pattern_w, pattern_h, -1 );
 
808
            if( pattern )
 
809
            {
 
810
                gdk_draw_pixbuf( pattern, gc, pix, 0, 0,
 
811
                                 0, 0, pattern_w, pattern_h, GDK_RGB_DITHER_NONE, 0, 0 );
 
812
                gdk_gc_set_tile( gc, pattern );
 
813
                gdk_gc_set_fill( gc, GDK_TILED );
 
814
        gdk_draw_rectangle( ((GtkWidget*)self)->window, gc, TRUE,
 
815
                            rect.x, rect.y, rect.width-1, rect.height-1 );
 
816
                g_object_unref( pattern );
 
817
                gdk_gc_set_fill( gc, GDK_SOLID );
 
818
            }
 
819
        }
 
820
        else
 
821
        {
 
822
            gdk_draw_pixbuf( ((GtkWidget*)self)->window, gc, pix, 0, 0,
 
823
                            rect.x, rect.y, rect.width, rect.height, GDK_RGB_DITHER_NONE, 0, 0 );
 
824
        }
 
825
        g_object_unref( pix );
 
826
    }
 
827
    else if( self->bg_type == DW_BG_COLOR ) /* draw background color */
 
828
    {
 
829
        GdkColor clr2 = self->bg;
 
830
        clr2.pixel = 0;
 
831
        clr2.red = clr2.red * clr->red / 65535;
 
832
        clr2.green = clr2.green * clr->green / 65535;
 
833
        clr2.blue = clr2.blue * clr->blue / 65535;
 
834
        gdk_gc_set_rgb_fg_color( gc, &clr2 );
 
835
        gdk_gc_set_fill( gc, GDK_SOLID );
 
836
        gdk_draw_rectangle( ((GtkWidget*)self)->window, gc, TRUE,
 
837
                            rect.x, rect.y, rect.width-1, rect.height-1 );
 
838
    }
 
839
 
 
840
    /* draw the border */
 
841
    gdk_gc_set_foreground( gc, clr );
 
842
    gdk_draw_rectangle( ((GtkWidget*)self)->window, gc, FALSE,
 
843
                        rect.x, rect.y, rect.width-1, rect.height-1 );
 
844
 
 
845
    gdk_color_free (clr);
 
846
    gdk_gc_destroy( gc );
 
847
}
 
848
 
 
849
static void update_rubberbanding( DesktopWindow* self, int newx, int newy )
 
850
{
 
851
    GList* l;
 
852
    GdkRectangle old_rect, new_rect;
 
853
    GdkRegion *region;
 
854
 
 
855
    calc_rubber_banding_rect(self, self->rubber_bending_x, self->rubber_bending_y, &old_rect );
 
856
    calc_rubber_banding_rect(self, newx, newy, &new_rect );
 
857
 
 
858
    gdk_window_invalidate_rect(((GtkWidget*)self)->window, &old_rect, FALSE );
 
859
    gdk_window_invalidate_rect(((GtkWidget*)self)->window, &new_rect, FALSE );
 
860
//    gdk_window_clear_area(((GtkWidget*)self)->window, new_rect.x, new_rect.y, new_rect.width, new_rect.height );
 
861
/*
 
862
    region = gdk_region_rectangle( &old_rect );
 
863
    gdk_region_union_with_rect( region, &new_rect );
 
864
 
 
865
//    gdk_window_invalidate_region( ((GtkWidget*)self)->window, &region, TRUE );
 
866
 
 
867
    gdk_region_destroy( region );
 
868
*/
 
869
    self->rubber_bending_x = newx;
 
870
    self->rubber_bending_y = newy;
 
871
 
 
872
    /* update selection */
 
873
    for( l = self->items; l; l = l->next )
 
874
    {
 
875
        DesktopItem* item = (DesktopItem*)l->data;
 
876
        gboolean selected;
 
877
        if( gdk_rectangle_intersect( &new_rect, &item->icon_rect, NULL ) ||
 
878
            gdk_rectangle_intersect( &new_rect, &item->text_rect, NULL ) )
 
879
            selected = TRUE;
 
880
        else
 
881
            selected = FALSE;
 
882
 
 
883
        if( item->is_selected != selected )
 
884
        {
 
885
            item->is_selected = selected;
 
886
            redraw_item( self, item );
 
887
        }
 
888
    }
 
889
}
 
890
 
 
891
gboolean on_button_press( GtkWidget* w, GdkEventButton* evt )
 
892
{
 
893
    DesktopWindow* self = (DesktopWindow*)w;
 
894
    DesktopItem *item, *clicked_item = NULL;
 
895
    GList* l;
 
896
 
 
897
    clicked_item = hit_test( w, (int)evt->x, (int)evt->y );
 
898
 
 
899
    if( evt->type == GDK_BUTTON_PRESS )
 
900
    {
 
901
        if( evt->button == 1 )  /* left button */
 
902
        {
 
903
            self->button_pressed = TRUE;    /* store button state for drag & drop */
 
904
            self->drag_start_x = evt->x;
 
905
            self->drag_start_y = evt->y;
 
906
        }
 
907
 
 
908
        /* if ctrl / shift is not pressed, deselect all. */
 
909
        if( ! (evt->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
 
910
        {
 
911
            /* don't cancel selection if clicking on selected items */
 
912
            if( !( (evt->button == 1 || evt->button == 3) && clicked_item && clicked_item->is_selected) )
 
913
            {
 
914
                for( l = self->items; l ;l = l->next )
 
915
                {
 
916
                    item = (DesktopItem*) l->data;
 
917
                    if( item->is_selected )
 
918
                    {
 
919
                        item->is_selected = FALSE;
 
920
                        redraw_item( self, item );
 
921
                    }
 
922
                }
 
923
            }
 
924
        }
 
925
 
 
926
        if( clicked_item )
 
927
        {
 
928
            if( evt->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK) )
 
929
                clicked_item->is_selected = ! clicked_item->is_selected;
 
930
            else
 
931
                clicked_item->is_selected = TRUE;
 
932
 
 
933
            if( self->focus && self->focus != item )
 
934
            {
 
935
                DesktopItem* old_focus = self->focus;
 
936
                if( old_focus )
 
937
                    redraw_item( w, old_focus );
 
938
            }
 
939
            self->focus = clicked_item;
 
940
            redraw_item( self, clicked_item );
 
941
 
 
942
            if( evt->button == 3 )  /* right click */
 
943
            {
 
944
                GList* sel = desktop_window_get_selected_items( self );
 
945
                if( sel )
 
946
                {
 
947
                    item = (DesktopItem*)sel->data;
 
948
                    GtkMenu* popup;
 
949
                    GList* l;
 
950
                    char* file_path = g_build_filename( vfs_get_desktop_dir(), item->fi->name, NULL );
 
951
                    /* FIXME: show popup menu for files */
 
952
                    for( l = sel; l; l = l->next )
 
953
                        l->data = vfs_file_info_ref( ((DesktopItem*)l->data)->fi );
 
954
                    popup = ptk_file_menu_new( file_path, item->fi, vfs_get_desktop_dir(), sel, NULL );
 
955
                    g_free( file_path );
 
956
 
 
957
                    gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
 
958
                }
 
959
            }
 
960
            goto out;
 
961
        }
 
962
        else /* no item is clicked */
 
963
        {
 
964
            if( evt->button == 3 )  /* right click on the blank area */
 
965
            {
 
966
                if( ! app_settings.show_wm_menu ) /* if our desktop menu is used */
 
967
                {
 
968
                    GtkWidget *popup, *sort_by_items[ 4 ], *sort_type_items[ 2 ];
 
969
                    int i;
 
970
                    /* show the desktop menu */
 
971
                    for( i = 0; i < 4; ++i )
 
972
                        icon_menu[ i ].ret = &sort_by_items[ i ];
 
973
                    for( i = 0; i < 2; ++i )
 
974
                        icon_menu[ 5 + i ].ret = &sort_type_items[ i ];
 
975
                    popup = ptk_menu_new_from_data( &desktop_menu, self, NULL );
 
976
                    gtk_check_menu_item_set_active( (GtkCheckMenuItem*)sort_by_items[ self->sort_by ], TRUE );
 
977
                    gtk_check_menu_item_set_active( (GtkCheckMenuItem*)sort_type_items[ self->sort_type ], TRUE );
 
978
                    gtk_widget_show_all(popup);
 
979
                    g_signal_connect( popup, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
 
980
 
 
981
                    gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
 
982
                    goto out;   /* don't forward the event to root win */
 
983
                }
 
984
            }
 
985
            else if( evt->button == 1 )
 
986
            {
 
987
                self->rubber_bending = TRUE;
 
988
 
 
989
                /* FIXME: if you foward the event here, this will break rubber bending... */
 
990
                /* forward the event to root window */
 
991
                /* forward_event_to_rootwin( gtk_widget_get_screen(w), evt ); */
 
992
 
 
993
                gtk_grab_add( w );
 
994
                self->rubber_bending_x = evt->x;
 
995
                self->rubber_bending_y = evt->y;
 
996
                goto out;
 
997
            }
 
998
        }
 
999
    }
 
1000
    else if( evt->type == GDK_2BUTTON_PRESS )
 
1001
    {
 
1002
        if( clicked_item && evt->button == 1)   /* left double click */
 
1003
        {
 
1004
            if( vfs_file_info_is_dir( clicked_item->fi ) )  /* this is a folder */
 
1005
            {
 
1006
                GList* sel_files = NULL;
 
1007
                sel_files = g_list_prepend( sel_files, clicked_item->fi );
 
1008
                open_folders( sel_files );
 
1009
                g_list_free( sel_files );
 
1010
            }
 
1011
            else /* regular files */
 
1012
            {
 
1013
                GList* sel_files = NULL;
 
1014
                sel_files = g_list_prepend( sel_files, clicked_item->fi );
 
1015
                ptk_open_files_with_app( vfs_get_desktop_dir(), sel_files, NULL, NULL );
 
1016
                g_list_free( sel_files );
 
1017
            }
 
1018
            goto out;
 
1019
        }
 
1020
    }
 
1021
    /* forward the event to root window */
 
1022
    forward_event_to_rootwin( gtk_widget_get_screen(w), evt );
 
1023
 
 
1024
out:
 
1025
    if( ! GTK_WIDGET_HAS_FOCUS(w) )
 
1026
    {
 
1027
        /* g_debug( "we don't have the focus, grab it!" ); */
 
1028
        gtk_widget_grab_focus( w );
 
1029
    }
 
1030
    return TRUE;
 
1031
}
 
1032
 
 
1033
gboolean on_button_release( GtkWidget* w, GdkEventButton* evt )
 
1034
{
 
1035
    DesktopWindow* self = (DesktopWindow*)w;
 
1036
 
 
1037
    self->button_pressed = FALSE;
 
1038
 
 
1039
    if( self->rubber_bending )
 
1040
    {
 
1041
        update_rubberbanding( self, evt->x, evt->y );
 
1042
        gtk_grab_remove( w );
 
1043
        self->rubber_bending = FALSE;
 
1044
    }
 
1045
    else if( self->dragging )
 
1046
    {
 
1047
        self->dragging = FALSE;
 
1048
    }
 
1049
 
 
1050
    /* forward the event to root window */
 
1051
    if( ! hit_test( w, (int)evt->x, (int)evt->y ) )
 
1052
        forward_event_to_rootwin( gtk_widget_get_screen(w), evt );
 
1053
 
 
1054
    return TRUE;
 
1055
}
 
1056
 
 
1057
gboolean on_mouse_move( GtkWidget* w, GdkEventMotion* evt )
 
1058
{
 
1059
    DesktopWindow* self = (DesktopWindow*)w;
 
1060
 
 
1061
    if( ! self->button_pressed )
 
1062
        return TRUE;
 
1063
 
 
1064
    if( self->dragging )
 
1065
    {
 
1066
    }
 
1067
    else if( self->rubber_bending )
 
1068
    {
 
1069
        update_rubberbanding( self, evt->x, evt->y );
 
1070
    }
 
1071
    else
 
1072
    {
 
1073
        if ( gtk_drag_check_threshold( w,
 
1074
                                    self->drag_start_x,
 
1075
                                    self->drag_start_y,
 
1076
                                    evt->x, evt->y))
 
1077
        {
 
1078
            GtkTargetList* target_list;
 
1079
            gboolean virtual_item = FALSE;
 
1080
            GList* sels = desktop_window_get_selected_items(self);
 
1081
 
 
1082
            self->dragging = TRUE;
 
1083
            if( sels && sels->next == NULL ) /* only one item selected */
 
1084
            {
 
1085
                DesktopItem* item = (DesktopItem*)sels->data;
 
1086
                if( item->fi->flags & VFS_FILE_INFO_VIRTUAL )
 
1087
                    virtual_item = TRUE;
 
1088
            }
 
1089
            g_list_free( sels );
 
1090
            if( virtual_item )
 
1091
                target_list = gtk_target_list_new( drag_targets + 1, G_N_ELEMENTS(drag_targets) - 1 );
 
1092
            else
 
1093
                target_list = gtk_target_list_new( drag_targets, G_N_ELEMENTS(drag_targets) );
 
1094
            gtk_drag_begin( w, target_list,
 
1095
                         GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK,
 
1096
                         1, evt );
 
1097
            gtk_target_list_unref( target_list );
 
1098
        }
 
1099
    }
 
1100
 
 
1101
    return TRUE;
 
1102
}
 
1103
 
 
1104
void on_drag_begin( GtkWidget* w, GdkDragContext* ctx )
 
1105
{
 
1106
    DesktopWindow* self = (DesktopWindow*)w;
 
1107
}
 
1108
 
 
1109
static GdkAtom get_best_target_at_dest( DesktopWindow* self, GdkDragContext* ctx, gint x, gint y )
 
1110
{
 
1111
    DesktopItem* item;
 
1112
    GdkAtom expected_target = 0;
 
1113
 
 
1114
    if( G_LIKELY(ctx->targets) )
 
1115
    {
 
1116
        if( ctx->action != GDK_ACTION_MOVE )
 
1117
            expected_target = text_uri_list_atom;
 
1118
        else
 
1119
        {
 
1120
            item = hit_test( self, x, y );
 
1121
            if( item )  /* drag over a desktpo item */
 
1122
            {
 
1123
                GList* sels;
 
1124
                sels = desktop_window_get_selected_items( self );
 
1125
                /* drag over the selected items themselves */
 
1126
                if( g_list_find( sels, item ) )
 
1127
                    expected_target = desktop_icon_atom;
 
1128
                else
 
1129
                    expected_target = text_uri_list_atom;
 
1130
                g_list_free( sels );
 
1131
            }
 
1132
            else    /* drag over blank area, check if it's a desktop icon first. */
 
1133
            {
 
1134
                if( g_list_find( ctx->targets, GUINT_TO_POINTER(desktop_icon_atom) ) )
 
1135
                    return desktop_icon_atom;
 
1136
                expected_target = text_uri_list_atom;
 
1137
            }
 
1138
        }
 
1139
        if( g_list_find( ctx->targets, GUINT_TO_POINTER(expected_target) ) )
 
1140
            return expected_target;
 
1141
    }
 
1142
    return GDK_NONE;
 
1143
}
 
1144
 
 
1145
#define GDK_ACTION_ALL  (GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK)
 
1146
 
 
1147
gboolean on_drag_motion( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time )
 
1148
{
 
1149
    DesktopWindow* self = (DesktopWindow*)w;
 
1150
    DesktopItem* item;
 
1151
    GdkAtom target;
 
1152
 
 
1153
    if( ! self->drag_entered )
 
1154
    {
 
1155
        self->drag_entered = TRUE;
 
1156
    }
 
1157
 
 
1158
    if( self->rubber_bending )
 
1159
    {
 
1160
        /* g_debug("rubber banding!"); */
 
1161
        return TRUE;
 
1162
    }
 
1163
 
 
1164
    /* g_debug( "suggest: %d, action = %d", ctx->suggested_action, ctx->action ); */
 
1165
 
 
1166
    if( g_list_find( ctx->targets, GUINT_TO_POINTER(text_uri_list_atom) ) )
 
1167
    {
 
1168
        GdkDragAction suggested_action = 0;
 
1169
        /* Only 'move' is available. The user force move action by pressing Shift key */
 
1170
        if( (ctx->actions & GDK_ACTION_ALL) == GDK_ACTION_MOVE )
 
1171
            suggested_action = GDK_ACTION_MOVE;
 
1172
        /* Only 'copy' is available. The user force copy action by pressing Ctrl key */
 
1173
        else if( (ctx->actions & GDK_ACTION_ALL) == GDK_ACTION_COPY )
 
1174
            suggested_action = GDK_ACTION_COPY;
 
1175
        /* Only 'link' is available. The user force link action by pressing Shift+Ctrl key */
 
1176
        else if( (ctx->actions & GDK_ACTION_ALL) == GDK_ACTION_LINK )
 
1177
            suggested_action = GDK_ACTION_LINK;
 
1178
        /* Several different actions are available. We have to figure out a good default action. */
 
1179
        else
 
1180
        {
 
1181
            if( get_best_target_at_dest(self, ctx, x, y ) == text_uri_list_atom )
 
1182
            {
 
1183
                self->pending_drop_action = TRUE;
 
1184
                /* check the status of drop site */
 
1185
                gtk_drag_get_data( w, ctx, text_uri_list_atom, time );
 
1186
                return TRUE;
 
1187
            }
 
1188
            else /* move desktop icon */
 
1189
            {
 
1190
                suggested_action = GDK_ACTION_MOVE;
 
1191
            }
 
1192
        }
 
1193
        ctx->action = suggested_action;
 
1194
        gdk_drag_status( ctx, suggested_action, time );
 
1195
    }
 
1196
    else if( g_list_find( ctx->targets, GUINT_TO_POINTER(desktop_icon_atom) ) ) /* moving desktop icon */
 
1197
    {
 
1198
        ctx->action = GDK_ACTION_MOVE;
 
1199
        gdk_drag_status( ctx, GDK_ACTION_MOVE, time );
 
1200
    }
 
1201
    else
 
1202
    {
 
1203
        gdk_drag_status (ctx, 0, time);
 
1204
    }
 
1205
    return TRUE;
 
1206
}
 
1207
 
 
1208
gboolean on_drag_drop( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time )
 
1209
{
 
1210
    DesktopWindow* self = (DesktopWindow*)w;
 
1211
    GdkAtom target = get_best_target_at_dest( self, ctx, x, y );
 
1212
    /* g_debug("DROP: %s!", gdk_atom_name(target) ); */
 
1213
    if( target == GDK_NONE )
 
1214
        return FALSE;
 
1215
    if( target == text_uri_list_atom || target == desktop_icon_atom )
 
1216
        gtk_drag_get_data( w, ctx, target, time );
 
1217
    return TRUE;
 
1218
}
 
1219
 
 
1220
void on_drag_data_get( GtkWidget* w, GdkDragContext* ctx, GtkSelectionData* data, guint info, guint time )
 
1221
{
 
1222
    DesktopWindow* self = (DesktopWindow*)w;
 
1223
    GList *sels, *l;
 
1224
    char* uri_list;
 
1225
    gsize len;
 
1226
 
 
1227
    if( info == DRAG_TARGET_URI_LIST )
 
1228
    {
 
1229
        GString *buf = g_string_sized_new( 4096 );
 
1230
 
 
1231
        sels = desktop_window_get_selected_files( self );
 
1232
 
 
1233
        for( l = sels; l; l = l->next )
 
1234
        {
 
1235
            VFSFileInfo* fi = (VFSFileInfo*)l->data;
 
1236
            char* path, *uri;
 
1237
 
 
1238
            if( fi->flags & VFS_FILE_INFO_VIRTUAL )
 
1239
                continue;
 
1240
 
 
1241
            path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
 
1242
            uri = g_filename_to_uri( path, NULL, NULL );
 
1243
            g_free( path );
 
1244
            g_string_append( buf, uri );
 
1245
            g_string_append( buf, "\r\n" );
 
1246
            g_free( uri );
 
1247
        }
 
1248
 
 
1249
        g_list_foreach( sels, vfs_file_info_unref, NULL );
 
1250
        g_list_free( sels );
 
1251
 
 
1252
        uri_list = g_convert( buf->str, buf->len, "ASCII", "UTF-8", NULL, &len, NULL);
 
1253
        g_string_free( buf, TRUE);
 
1254
 
 
1255
        if( uri_list )
 
1256
        {
 
1257
            gtk_selection_data_set( data,
 
1258
                      text_uri_list_atom,
 
1259
                      8, (guchar *)uri_list, len );
 
1260
            g_free (uri_list);
 
1261
        }
 
1262
    }
 
1263
    else if( info == DRAG_TARGET_DESKTOP_ICON )
 
1264
    {
 
1265
    }
 
1266
}
 
1267
 
 
1268
static char** get_files_from_selection_data(GtkSelectionData* data)
 
1269
{
 
1270
    char** files = gtk_selection_data_get_uris(data), **pfile;
 
1271
    if( files )
 
1272
    {
 
1273
        /* convert uris to filenames */
 
1274
        for( pfile = files; *pfile; ++pfile )
 
1275
        {
 
1276
            char* file = g_filename_from_uri( *pfile, NULL, NULL );
 
1277
            g_free( *pfile );
 
1278
            *pfile = file;
 
1279
        }
 
1280
    }
 
1281
    return files;
 
1282
}
 
1283
 
 
1284
void on_drag_data_received( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, GtkSelectionData* data, guint info, guint time )
 
1285
{
 
1286
    DesktopWindow* self = (DesktopWindow*)w;
 
1287
 
 
1288
    if( data->target == text_uri_list_atom )
 
1289
    {
 
1290
        DesktopItem* item = hit_test( self, x, y );
 
1291
        char* dest_dir = NULL;
 
1292
        VFSFileTaskType file_action = VFS_FILE_TASK_MOVE;
 
1293
        PtkFileTask* task = NULL;
 
1294
        char** files;
 
1295
        int n, i;
 
1296
        GList* file_list;
 
1297
 
 
1298
        if( (data->length < 0) || (data->format != 8) )
 
1299
        {
 
1300
            gtk_drag_finish( ctx, FALSE, FALSE, time );
 
1301
            return;
 
1302
        }
 
1303
 
 
1304
        if( item )
 
1305
        {
 
1306
            if( (item->fi->flags & VFS_FILE_INFO_VIRTUAL) && vfs_file_info_is_dir( item->fi ) )
 
1307
                dest_dir = g_build_filename( vfs_get_desktop_dir(), item->fi->name, NULL );
 
1308
        }
 
1309
 
 
1310
        /* We are just checking the suggested actions for the drop site, not really drop */
 
1311
        if( self->pending_drop_action )
 
1312
        {
 
1313
            GdkDragAction suggested_action = 0;
 
1314
            dev_t dest_dev;
 
1315
            struct stat statbuf;
 
1316
 
 
1317
            if( stat( dest_dir ? dest_dir : vfs_get_desktop_dir(), &statbuf ) == 0 )
 
1318
            {
 
1319
                dest_dev = statbuf.st_dev;
 
1320
                if( 0 == self->drag_src_dev )
 
1321
                {
 
1322
                    char** pfile;
 
1323
                    files = get_files_from_selection_data(data);
 
1324
                    self->drag_src_dev = dest_dev;
 
1325
                    if( files )
 
1326
                    {
 
1327
                        for( pfile = files; *pfile; ++pfile )
 
1328
                        {
 
1329
                            if( stat( *pfile, &statbuf ) == 0 && statbuf.st_dev != dest_dev )
 
1330
                            {
 
1331
                                self->drag_src_dev = statbuf.st_dev;
 
1332
                                break;
 
1333
                            }
 
1334
                        }
 
1335
                    }
 
1336
                    g_strfreev( files );
 
1337
                }
 
1338
 
 
1339
                if( self->drag_src_dev != dest_dev )     /* src and dest are on different devices */
 
1340
                    suggested_action = GDK_ACTION_COPY;
 
1341
                else
 
1342
                    suggested_action = GDK_ACTION_MOVE;
 
1343
            }
 
1344
            g_free( dest_dir );
 
1345
            self->pending_drop_action = FALSE;
 
1346
            gdk_drag_status( ctx, suggested_action, time );
 
1347
            return;
 
1348
        }
 
1349
 
 
1350
        switch ( ctx->action )
 
1351
        {
 
1352
        case GDK_ACTION_COPY:
 
1353
            file_action = VFS_FILE_TASK_COPY;
 
1354
            break;
 
1355
        case GDK_ACTION_LINK:
 
1356
            file_action = VFS_FILE_TASK_LINK;
 
1357
            break;
 
1358
            /* FIXME:
 
1359
              GDK_ACTION_DEFAULT, GDK_ACTION_PRIVATE, and GDK_ACTION_ASK are not handled */
 
1360
        default:
 
1361
            break;
 
1362
        }
 
1363
 
 
1364
        files = get_files_from_selection_data( data );
 
1365
        /* g_debug("file_atcion: %d", file_action); */
 
1366
        file_list = NULL;
 
1367
        n = g_strv_length( files );
 
1368
        for( i = 0; i < n; ++i )
 
1369
            file_list = g_list_prepend( file_list, files[i] );
 
1370
        g_free( files );
 
1371
 
 
1372
        task = ptk_file_task_new( file_action,
 
1373
                                  file_list,
 
1374
                                  dest_dir ? dest_dir : vfs_get_desktop_dir(),
 
1375
                                  GTK_WINDOW( self ) );
 
1376
        ptk_file_task_run( task );
 
1377
 
 
1378
        g_free( dest_dir );
 
1379
 
 
1380
        gtk_drag_finish( ctx, TRUE, FALSE, time );
 
1381
    }
 
1382
    else if( data->target == desktop_icon_atom ) /* moving desktop icon */
 
1383
    {
 
1384
        GList* sels = desktop_window_get_selected_items(self), *l;
 
1385
        int x_off = x - self->drag_start_x;
 
1386
        int y_off = y - self->drag_start_y;
 
1387
        for( l = sels; l; l = l->next )
 
1388
        {
 
1389
            DesktopItem* item = l->data;
 
1390
            #if 0   /* temporarily turn off */
 
1391
            move_item( self, item, x_off, y_off, TRUE );
 
1392
            #endif
 
1393
            /* g_debug( "move: %d, %d", x_off, y_off ); */
 
1394
        }
 
1395
        g_list_free( sels );
 
1396
        gtk_drag_finish( ctx, TRUE, FALSE, time );
 
1397
    }
 
1398
}
 
1399
 
 
1400
void on_drag_leave( GtkWidget* w, GdkDragContext* ctx, guint time )
 
1401
{
 
1402
    DesktopWindow* self = (DesktopWindow*)w;
 
1403
    self->drag_entered = FALSE;
 
1404
    self->drag_src_dev = 0;
 
1405
}
 
1406
 
 
1407
void on_drag_end( GtkWidget* w, GdkDragContext* ctx )
 
1408
{
 
1409
    DesktopWindow* self = (DesktopWindow*)w;
 
1410
}
 
1411
 
 
1412
gboolean on_key_press( GtkWidget* w, GdkEventKey* evt )
 
1413
{
 
1414
    GList* sels;
 
1415
    DesktopWindow* self = (DesktopWindow*)w;
 
1416
    int modifier = ( evt->state & ( GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK ) );
 
1417
 
 
1418
    sels = desktop_window_get_selected_files( self );
 
1419
 
 
1420
    if ( modifier == GDK_CONTROL_MASK )
 
1421
    {
 
1422
        switch ( evt->keyval )
 
1423
        {
 
1424
        case GDK_x:
 
1425
            if( sels )
 
1426
                ptk_clipboard_cut_or_copy_files( vfs_get_desktop_dir(), sels, FALSE );
 
1427
            break;
 
1428
        case GDK_c:
 
1429
            if( sels )
 
1430
                ptk_clipboard_cut_or_copy_files( vfs_get_desktop_dir(), sels, TRUE );
 
1431
            break;
 
1432
        case GDK_v:
 
1433
            on_paste( NULL, self );
 
1434
            break;
 
1435
/*
 
1436
        case GDK_i:
 
1437
            ptk_file_browser_invert_selection( file_browser );
 
1438
            break;
 
1439
        case GDK_a:
 
1440
            ptk_file_browser_select_all( file_browser );
 
1441
            break;
 
1442
*/
 
1443
        }
 
1444
    }
 
1445
    else if ( modifier == GDK_MOD1_MASK )
 
1446
    {
 
1447
        switch ( evt->keyval )
 
1448
        {
 
1449
        case GDK_Return:
 
1450
            if( sels )
 
1451
                ptk_show_file_properties( NULL, vfs_get_desktop_dir(), sels );
 
1452
            break;
 
1453
        }
 
1454
    }
 
1455
    else if ( modifier == 0 )
 
1456
    {
 
1457
        switch ( evt->keyval )
 
1458
        {
 
1459
        case GDK_F2:
 
1460
            if( sels )
 
1461
                ptk_rename_file( NULL, vfs_get_desktop_dir(), (VFSFileInfo*)sels->data );
 
1462
            break;
 
1463
        case GDK_Delete:
 
1464
            if( sels )
 
1465
                ptk_delete_files( NULL, vfs_get_desktop_dir(), sels );
 
1466
            break;
 
1467
        }
 
1468
    }
 
1469
 
 
1470
    if( sels )
 
1471
        vfs_file_info_list_free( sels );
 
1472
 
 
1473
    return TRUE;
 
1474
}
 
1475
 
 
1476
void on_style_set( GtkWidget* w, GtkStyle* prev )
 
1477
{
 
1478
    DesktopWindow* self = (DesktopWindow*)w;
 
1479
 
 
1480
    PangoContext* pc;
 
1481
    PangoFontMetrics *metrics;
 
1482
    int font_h;
 
1483
    pc = gtk_widget_get_pango_context( (GtkWidget*)self );
 
1484
 
 
1485
    metrics = pango_context_get_metrics(
 
1486
                            pc, ((GtkWidget*)self)->style->font_desc,
 
1487
                            pango_context_get_language(pc));
 
1488
 
 
1489
    font_h = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent (metrics);
 
1490
    font_h /= PANGO_SCALE;
 
1491
}
 
1492
 
 
1493
void on_realize( GtkWidget* w )
 
1494
{
 
1495
    guint32 val;
 
1496
    DesktopWindow* self = (DesktopWindow*)w;
 
1497
 
 
1498
    GTK_WIDGET_CLASS(parent_class)->realize( w );
 
1499
    gdk_window_set_type_hint( w->window,
 
1500
                              GDK_WINDOW_TYPE_HINT_DESKTOP );
 
1501
 
 
1502
    gtk_window_set_skip_pager_hint( GTK_WINDOW(w), TRUE );
 
1503
    gtk_window_set_skip_taskbar_hint( GTK_WINDOW(w), TRUE );
 
1504
    gtk_window_set_resizable( (GtkWindow*)w, FALSE );
 
1505
 
 
1506
    /* This is borrowed from fbpanel */
 
1507
#define WIN_HINTS_SKIP_FOCUS      (1<<0)    /* skip "alt-tab" */
 
1508
    val = WIN_HINTS_SKIP_FOCUS;
 
1509
    XChangeProperty(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(w->window),
 
1510
          XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
 
1511
          PropModeReplace, (unsigned char *) &val, 1);
 
1512
 
 
1513
    if( ! self->gc )
 
1514
        self->gc = gdk_gc_new( w->window );
 
1515
 
 
1516
//    if( self->background )
 
1517
//        gdk_window_set_back_pixmap( w->window, self->background, FALSE );
 
1518
}
 
1519
 
 
1520
gboolean on_focus_in( GtkWidget* w, GdkEventFocus* evt )
 
1521
{
 
1522
    DesktopWindow* self = (DesktopWindow*) w;
 
1523
    GTK_WIDGET_SET_FLAGS( w, GTK_HAS_FOCUS );
 
1524
    if( self->focus )
 
1525
        redraw_item( self, self->focus );
 
1526
    return FALSE;
 
1527
}
 
1528
 
 
1529
gboolean on_focus_out( GtkWidget* w, GdkEventFocus* evt )
 
1530
{
 
1531
    DesktopWindow* self = (DesktopWindow*) w;
 
1532
    if( self->focus )
 
1533
    {
 
1534
        GTK_WIDGET_UNSET_FLAGS( w, GTK_HAS_FOCUS );
 
1535
        redraw_item( self, self->focus );
 
1536
    }
 
1537
    return FALSE;
 
1538
}
 
1539
 
 
1540
/*
 
1541
gboolean on_scroll( GtkWidget *w, GdkEventScroll *evt, gpointer user_data )
 
1542
{
 
1543
    forward_event_to_rootwin( gtk_widget_get_screen( w ), ( GdkEvent* ) evt );
 
1544
    return TRUE;
 
1545
}
 
1546
*/
 
1547
 
 
1548
 
 
1549
void on_sort_by_name ( GtkMenuItem *menuitem, DesktopWindow* self )
 
1550
{
 
1551
    desktop_window_sort_items( self, DW_SORT_BY_NAME, self->sort_type );
 
1552
}
 
1553
 
 
1554
void on_sort_by_size ( GtkMenuItem *menuitem, DesktopWindow* self )
 
1555
{
 
1556
    desktop_window_sort_items( self, DW_SORT_BY_SIZE, self->sort_type );
 
1557
}
 
1558
 
 
1559
void on_sort_by_mtime ( GtkMenuItem *menuitem, DesktopWindow* self )
 
1560
{
 
1561
    desktop_window_sort_items( self, DW_SORT_BY_MTIME, self->sort_type );
 
1562
}
 
1563
 
 
1564
void on_sort_by_type ( GtkMenuItem *menuitem, DesktopWindow* self )
 
1565
{
 
1566
    desktop_window_sort_items( self, DW_SORT_BY_TYPE, self->sort_type );
 
1567
}
 
1568
 
 
1569
void on_sort_custom( GtkMenuItem *menuitem, DesktopWindow* self )
 
1570
{
 
1571
    desktop_window_sort_items( self, DW_SORT_CUSTOM, self->sort_type );
 
1572
}
 
1573
 
 
1574
void on_sort_ascending( GtkMenuItem *menuitem, DesktopWindow* self )
 
1575
{
 
1576
    desktop_window_sort_items( self, self->sort_by, GTK_SORT_ASCENDING );
 
1577
}
 
1578
 
 
1579
void on_sort_descending( GtkMenuItem *menuitem, DesktopWindow* self )
 
1580
{
 
1581
    desktop_window_sort_items( self, self->sort_by, GTK_SORT_DESCENDING );
 
1582
}
 
1583
 
 
1584
void on_paste( GtkMenuItem *menuitem, DesktopWindow* self )
 
1585
{
 
1586
    const gchar* dest_dir = vfs_get_desktop_dir();
 
1587
    ptk_clipboard_paste_files( NULL, dest_dir );
 
1588
}
 
1589
 
 
1590
void
 
1591
on_popup_new_folder_activate ( GtkMenuItem *menuitem,
 
1592
                               gpointer data )
 
1593
{
 
1594
    ptk_create_new_file( NULL,  vfs_get_desktop_dir(), TRUE, NULL );
 
1595
}
 
1596
 
 
1597
void
 
1598
on_popup_new_text_file_activate ( GtkMenuItem *menuitem,
 
1599
                                  gpointer data )
 
1600
{
 
1601
    ptk_create_new_file( NULL,  vfs_get_desktop_dir(), FALSE, NULL );
 
1602
}
 
1603
 
 
1604
void on_settings( GtkMenuItem *menuitem, DesktopWindow* self )
 
1605
{
 
1606
    fm_edit_preference( NULL, PREF_DESKTOP );
 
1607
}
 
1608
 
 
1609
 
 
1610
/* private methods */
 
1611
 
 
1612
void calc_item_size( DesktopWindow* self, DesktopItem* item )
 
1613
{
 
1614
    PangoLayoutLine* line;
 
1615
    int line_h;
 
1616
 
 
1617
    item->box.width = self->item_w;
 
1618
    item->box.height = self->y_pad * 2;
 
1619
    item->box.height += self->icon_size;
 
1620
    item->box.height += self->spacing;
 
1621
 
 
1622
    pango_layout_set_text( self->pl, item->fi->disp_name, -1 );
 
1623
    pango_layout_set_wrap( self->pl, PANGO_WRAP_WORD_CHAR );    /* wrap the text */
 
1624
    pango_layout_set_ellipsize( self->pl, PANGO_ELLIPSIZE_NONE );
 
1625
 
 
1626
    if( pango_layout_get_line_count(self->pl) >= 2 ) /* there are more than 2 lines */
 
1627
    {
 
1628
        /* we only allow displaying two lines, so let's get the second line */
 
1629
/* Pango only provide version check macros in the latest versions...
 
1630
 *  So there is no point in making this check.
 
1631
 *  FIXME: this check should be done ourselves in configure.
 
1632
  */
 
1633
#if defined (PANGO_VERSION_CHECK)
 
1634
#if PANGO_VERSION_CHECK( 1, 16, 0 )
 
1635
        line = pango_layout_get_line_readonly( self->pl, 1 );
 
1636
#else
 
1637
        line = pango_layout_get_line( self->pl, 1 );
 
1638
#endif
 
1639
#else
 
1640
        line = pango_layout_get_line( self->pl, 1 );
 
1641
#endif
 
1642
        item->len1 = line->start_index; /* this the position where the first line wraps */
 
1643
 
 
1644
        /* OK, now we layout these 2 lines separately */
 
1645
        pango_layout_set_text( self->pl, item->fi->disp_name, item->len1 );
 
1646
        pango_layout_get_pixel_size( self->pl, NULL, &line_h );
 
1647
        item->text_rect.height = line_h;
 
1648
    }
 
1649
    else
 
1650
    {
 
1651
        item->text_rect.height = 0;
 
1652
    }
 
1653
 
 
1654
    pango_layout_set_wrap( self->pl, 0 );    /* wrap the text */
 
1655
    pango_layout_set_ellipsize( self->pl, PANGO_ELLIPSIZE_END );
 
1656
 
 
1657
    pango_layout_set_text( self->pl, item->fi->disp_name + item->len1, -1 );
 
1658
    pango_layout_get_pixel_size( self->pl, NULL, &line_h );
 
1659
    item->text_rect.height += line_h;
 
1660
 
 
1661
    item->text_rect.width = 100;
 
1662
    item->box.height += item->text_rect.height;
 
1663
 
 
1664
    item->icon_rect.width = item->icon_rect.height = self->icon_size;
 
1665
}
 
1666
 
 
1667
void layout_items( DesktopWindow* self )
 
1668
{
 
1669
    GList* l;
 
1670
    DesktopItem* item;
 
1671
    GtkWidget* widget = (GtkWidget*)self;
 
1672
    int x, y, w, y2;
 
1673
 
 
1674
    self->item_w = MAX( self->label_w, self->icon_size ) + self->x_pad * 2;
 
1675
 
 
1676
    x = self->wa.x + self->x_margin;
 
1677
    y = self->wa.y + self->y_margin;
 
1678
 
 
1679
    pango_layout_set_width( self->pl, 100 * PANGO_SCALE );
 
1680
 
 
1681
    for( l = self->items; l; l = l->next )
 
1682
    {
 
1683
        item = (DesktopItem*)l->data;
 
1684
 
 
1685
        item->box.x = x;
 
1686
        item->box.y = y;
 
1687
 
 
1688
        item->box.width = self->item_w;
 
1689
        calc_item_size( self, item );
 
1690
 
 
1691
        y2 = self->wa.y + self->wa.height - self->y_margin; /* bottom */
 
1692
        if( y + item->box.height > y2 ) /* bottom is reached */
 
1693
        {
 
1694
            y = self->wa.y + self->y_margin;
 
1695
            item->box.y = y;
 
1696
            y += item->box.height;
 
1697
            x += self->item_w;  /* go to the next column */
 
1698
            item->box.x = x;
 
1699
        }
 
1700
        else /* bottom is not reached */
 
1701
        {
 
1702
            y += item->box.height;  /* move to the next row */
 
1703
        }
 
1704
 
 
1705
        item->icon_rect.x = item->box.x + (item->box.width - self->icon_size) / 2;
 
1706
        item->icon_rect.y = item->box.y + self->y_pad;
 
1707
 
 
1708
        item->text_rect.x = item->box.x + self->x_pad;
 
1709
        item->text_rect.y = item->box.y + self->y_pad + self->icon_size + self->spacing;
 
1710
    }
 
1711
    gtk_widget_queue_draw( self );
 
1712
}
 
1713
 
 
1714
void on_file_listed( VFSDir* dir, gboolean is_cancelled, DesktopWindow* self )
 
1715
{
 
1716
    GList* l, *items = NULL;
 
1717
    VFSFileInfo* fi;
 
1718
    DesktopItem* item;
 
1719
 
 
1720
    g_mutex_lock( dir->mutex );
 
1721
    for( l = dir->file_list; l; l = l->next )
 
1722
    {
 
1723
        fi = (VFSFileInfo*)l->data;
 
1724
        if( fi->name[0] == '.' )    /* skip the hidden files */
 
1725
            continue;
 
1726
        item = g_slice_new0( DesktopItem );
 
1727
        item->fi = vfs_file_info_ref( fi );
 
1728
        items = g_list_prepend( items, item );
 
1729
                /* item->icon = vfs_file_info_get_big_icon( fi ); */
 
1730
 
 
1731
        if( vfs_file_info_is_image( fi ) )
 
1732
            vfs_thumbnail_loader_request( dir, fi, TRUE );
 
1733
    }
 
1734
    g_mutex_unlock( dir->mutex );
 
1735
 
 
1736
    self->items = NULL;
 
1737
    self->items = g_list_sort_with_data( items, get_sort_func(self), self );
 
1738
 
 
1739
    /* Make an item for Home dir */
 
1740
    fi = vfs_file_info_new();
 
1741
    fi->disp_name = g_strdup( _("My Documents") );
 
1742
    fi->mime_type = vfs_mime_type_get_from_type( XDG_MIME_TYPE_DIRECTORY );
 
1743
    fi->name = g_strdup( g_get_home_dir() );
 
1744
    fi->mode |= S_IFDIR;
 
1745
    fi->flags |= VFS_FILE_INFO_VIRTUAL; /* this is a virtual file which doesn't exist on the file system */
 
1746
    fi->big_thumbnail = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gnome-fs-home", self->icon_size, 0, NULL );
 
1747
    if( ! fi->big_thumbnail )
 
1748
        fi->big_thumbnail = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "folder-home", self->icon_size, 0, NULL );
 
1749
 
 
1750
    item = g_slice_new0( DesktopItem );
 
1751
    item->fi = fi;
 
1752
        /* item->icon = vfs_file_info_get_big_thumbnail( fi ); */
 
1753
 
 
1754
    self->items = g_list_prepend( self->items, item );
 
1755
 
 
1756
    layout_items( self );
 
1757
}
 
1758
 
 
1759
void on_thumbnail_loaded( VFSDir* dir,  VFSFileInfo* fi, DesktopWindow* self )
 
1760
{
 
1761
    GList* l;
 
1762
    GtkWidget* w = (GtkWidget*)self;
 
1763
 
 
1764
    for( l = self->items; l; l = l->next )
 
1765
    {
 
1766
        DesktopItem* item = (DesktopItem*) l->data;
 
1767
        if( item->fi == fi )
 
1768
        {
 
1769
/*
 
1770
                if( item->icon )
 
1771
                        g_object_unref( item->icon );
 
1772
                item->icon = vfs_file_info_get_big_thumbnail( fi );
 
1773
*/
 
1774
            redraw_item( self, item );
 
1775
            return;
 
1776
        }
 
1777
    }
 
1778
}
 
1779
 
 
1780
void on_file_created( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
 
1781
{
 
1782
    GList *l;
 
1783
    DesktopWindow* self = (DesktopWindow*)user_data;
 
1784
    DesktopItem* item;
 
1785
 
 
1786
    /* don't show hidden files */
 
1787
    if( file->name[0] == '.' )
 
1788
        return;
 
1789
 
 
1790
    /* prevent duplicated items */
 
1791
    for( l = self->items; l; l = l->next )
 
1792
    {
 
1793
        item = (DesktopItem*)l->data;
 
1794
        if( strcmp( file->name, item->fi->name ) == 0 )
 
1795
            return;
 
1796
    }
 
1797
 
 
1798
    item = g_slice_new0( DesktopItem );
 
1799
    item->fi = vfs_file_info_ref( file );
 
1800
    /* item->icon = vfs_file_info_get_big_icon( file ); */
 
1801
 
 
1802
    self->items = g_list_insert_sorted_with_data( self->items, item,
 
1803
                                                                            get_sort_func(self), self );
 
1804
 
 
1805
    /* FIXME: we shouldn't update the whole screen */
 
1806
    /* FIXME: put this in idle handler with priority higher than redraw but lower than resize */
 
1807
    layout_items( self );
 
1808
}
 
1809
 
 
1810
void on_file_deleted( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
 
1811
{
 
1812
    GList *l;
 
1813
    DesktopWindow* self = (DesktopWindow*)user_data;
 
1814
    DesktopItem* item;
 
1815
 
 
1816
    /* FIXME: special handling is needed here */
 
1817
    if( ! file )
 
1818
        return;
 
1819
 
 
1820
    /* don't deal with hidden files */
 
1821
    if( file->name[0] == '.' )
 
1822
        return;
 
1823
 
 
1824
    /* find items */
 
1825
    for( l = self->items; l; l = l->next )
 
1826
    {
 
1827
        item = (DesktopItem*)l->data;
 
1828
        if( item->fi == file )
 
1829
            break;
 
1830
    }
 
1831
 
 
1832
    if( l ) /* found */
 
1833
    {
 
1834
        item = (DesktopItem*)l->data;
 
1835
        self->items = g_list_delete_link( self->items, l );
 
1836
        desktop_item_free( item );
 
1837
        /* FIXME: we shouldn't update the whole screen */
 
1838
        /* FIXME: put this in idle handler with priority higher than redraw but lower than resize */
 
1839
        layout_items( self );
 
1840
    }
 
1841
}
 
1842
 
 
1843
void on_file_changed( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
 
1844
{
 
1845
    GList *l;
 
1846
    DesktopWindow* self = (DesktopWindow*)user_data;
 
1847
    DesktopItem* item;
 
1848
    GtkWidget* w = (GtkWidget*)self;
 
1849
 
 
1850
    /* don't touch hidden files */
 
1851
    if( file->name[0] == '.' )
 
1852
        return;
 
1853
 
 
1854
    /* find items */
 
1855
    for( l = self->items; l; l = l->next )
 
1856
    {
 
1857
        item = (DesktopItem*)l->data;
 
1858
        if( item->fi == file )
 
1859
            break;
 
1860
    }
 
1861
 
 
1862
    if( l ) /* found */
 
1863
    {
 
1864
        item = (DesktopItem*)l->data;
 
1865
        /*
 
1866
   if( item->icon )
 
1867
                g_object_unref( item->icon );
 
1868
                item->icon = vfs_file_info_get_big_icon( file );
 
1869
                */
 
1870
        if( GTK_WIDGET_VISIBLE( w ) )
 
1871
        {
 
1872
            /* redraw the item */
 
1873
            redraw_item( self, item );
 
1874
        }
 
1875
    }
 
1876
}
 
1877
 
 
1878
 
 
1879
/*-------------- Private methods -------------------*/
 
1880
 
 
1881
void paint_item( DesktopWindow* self, DesktopItem* item, GdkRectangle* expose_area )
 
1882
{
 
1883
    /* GdkPixbuf* icon = item->icon ? gdk_pixbuf_ref(item->icon) : NULL; */
 
1884
    GdkPixbuf* icon;
 
1885
    const char* text = item->fi->disp_name;
 
1886
    GtkWidget* widget = (GtkWidget*)self;
 
1887
    GdkDrawable* drawable = widget->window;
 
1888
    GdkGC* tmp;
 
1889
    GtkCellRendererState state = 0;
 
1890
    GdkRectangle text_rect;
 
1891
    int w, h;
 
1892
 
 
1893
    if( item->fi->big_thumbnail )
 
1894
        icon = gdk_pixbuf_ref( item->fi->big_thumbnail );
 
1895
    else
 
1896
        icon = vfs_file_info_get_big_icon( item->fi );
 
1897
 
 
1898
    if( item->is_selected )
 
1899
        state = GTK_CELL_RENDERER_SELECTED;
 
1900
 
 
1901
    g_object_set( self->icon_render, "pixbuf", icon, NULL );
 
1902
    gtk_cell_renderer_render( self->icon_render, drawable, widget,
 
1903
                                                       &item->icon_rect, &item->icon_rect, expose_area, state );
 
1904
 
 
1905
        if( icon )
 
1906
                g_object_unref( icon );
 
1907
 
 
1908
    tmp = widget->style->fg_gc[0];
 
1909
 
 
1910
    text_rect = item->text_rect;
 
1911
 
 
1912
    pango_layout_set_wrap( self->pl, 0 );
 
1913
 
 
1914
    if( item->is_selected )
 
1915
    {
 
1916
        GdkRectangle intersect={0};
 
1917
 
 
1918
        if( gdk_rectangle_intersect( expose_area, &item->text_rect, &intersect ) )
 
1919
            gdk_draw_rectangle( widget->window,
 
1920
                        widget->style->bg_gc[GTK_STATE_SELECTED],
 
1921
                        TRUE, intersect.x, intersect.y, intersect.width, intersect.height );
 
1922
    }
 
1923
    else
 
1924
    {
 
1925
        /* Do the drop shadow stuff...  This is a little bit dirty... */
 
1926
        ++text_rect.x;
 
1927
        ++text_rect.y;
 
1928
 
 
1929
        gdk_gc_set_foreground( self->gc, &self->shadow );
 
1930
 
 
1931
        if( item->len1 > 0 )
 
1932
        {
 
1933
            pango_layout_set_text( self->pl, text, item->len1 );
 
1934
            pango_layout_get_pixel_size( self->pl, &w, &h );
 
1935
            gdk_draw_layout( widget->window, self->gc, text_rect.x, text_rect.y, self->pl );
 
1936
            text_rect.y += h;
 
1937
        }
 
1938
        pango_layout_set_text( self->pl, text + item->len1, -1 );
 
1939
        pango_layout_set_ellipsize( self->pl, PANGO_ELLIPSIZE_END );
 
1940
        gdk_draw_layout( widget->window, self->gc, text_rect.x, text_rect.y, self->pl );
 
1941
 
 
1942
        --text_rect.x;
 
1943
        --text_rect.y;
 
1944
    }
 
1945
 
 
1946
    if( self->focus == item && GTK_WIDGET_HAS_FOCUS(widget) )
 
1947
    {
 
1948
        gtk_paint_focus( widget->style, widget->window,
 
1949
                        GTK_STATE_NORMAL,/*item->is_selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,*/
 
1950
                        &item->text_rect, widget, "icon_view",
 
1951
                        item->text_rect.x, item->text_rect.y,
 
1952
                        item->text_rect.width, item->text_rect.height);
 
1953
    }
 
1954
 
 
1955
    text_rect = item->text_rect;
 
1956
 
 
1957
    gdk_gc_set_foreground( self->gc, &self->fg );
 
1958
 
 
1959
    if( item->len1 > 0 )
 
1960
    {
 
1961
        pango_layout_set_text( self->pl, text, item->len1 );
 
1962
        pango_layout_get_pixel_size( self->pl, &w, &h );
 
1963
        gdk_draw_layout( widget->window, self->gc, text_rect.x, text_rect.y, self->pl );
 
1964
        text_rect.y += h;
 
1965
    }
 
1966
    pango_layout_set_text( self->pl, text + item->len1, -1 );
 
1967
    pango_layout_set_ellipsize( self->pl, PANGO_ELLIPSIZE_END );
 
1968
    gdk_draw_layout( widget->window, self->gc, text_rect.x, text_rect.y, self->pl );
 
1969
 
 
1970
    widget->style->fg_gc[0] = tmp;
 
1971
}
 
1972
 
 
1973
void move_item( DesktopWindow* self, DesktopItem* item, int x, int y, gboolean is_offset )
 
1974
{
 
1975
    GdkRectangle old = item->box;
 
1976
 
 
1977
    if( ! is_offset )
 
1978
    {
 
1979
        x -= item->box.x;
 
1980
        y -= item->box.y;
 
1981
    }
 
1982
    item->box.x += x;
 
1983
    item->box.y += y;
 
1984
    item->icon_rect.x += x;
 
1985
    item->icon_rect.y += y;
 
1986
    item->text_rect.x += x;
 
1987
    item->text_rect.y += y;
 
1988
 
 
1989
    gtk_widget_queue_draw_area( (GtkWidget*)self, old.x, old.y, old.width, old.height );
 
1990
    gtk_widget_queue_draw_area( (GtkWidget*)self, item->box.x, item->box.y, item->box.width, item->box.height );
 
1991
}
 
1992
 
 
1993
static gboolean is_point_in_rect( GdkRectangle* rect, int x, int y )
 
1994
{
 
1995
    return rect->x < x && x < (rect->x + rect->width) && y > rect->y && y < (rect->y + rect->height);
 
1996
}
 
1997
 
 
1998
DesktopItem* hit_test( DesktopWindow* self, int x, int y )
 
1999
{
 
2000
    DesktopItem* item;
 
2001
    GList* l;
 
2002
    for( l = self->items; l; l = l->next )
 
2003
    {
 
2004
        item = (DesktopItem*) l->data;
 
2005
        if( is_point_in_rect( &item->icon_rect, x, y )
 
2006
         || is_point_in_rect( &item->text_rect, x, y ) )
 
2007
            return item;
 
2008
    }
 
2009
    return NULL;
 
2010
}
 
2011
 
 
2012
/* FIXME: this is too dirty and here is some redundant code.
 
2013
 *  We really need better and cleaner APIs for this */
 
2014
void open_folders( GList* folders )
 
2015
{
 
2016
    FMMainWindow* main_window = fm_main_window_new();
 
2017
    FM_MAIN_WINDOW( main_window ) ->splitter_pos = app_settings.splitter_pos;
 
2018
    gtk_window_set_default_size( GTK_WINDOW( main_window ),
 
2019
                                 app_settings.width,
 
2020
                                 app_settings.height );
 
2021
    gtk_widget_show( main_window );
 
2022
    while( folders )
 
2023
    {
 
2024
        VFSFileInfo* fi = (VFSFileInfo*)folders->data;
 
2025
        char* path;
 
2026
        if( fi->flags & VFS_FILE_INFO_VIRTUAL )
 
2027
        {
 
2028
            /* if this is a special item, not a real file in desktop dir */
 
2029
            if( fi->name[0] == '/' )   /* it's a real path */
 
2030
            {
 
2031
                path = g_strdup( fi->name );
 
2032
            }
 
2033
            else
 
2034
            {
 
2035
                folders = folders->next;
 
2036
                continue;
 
2037
            }
 
2038
            /* FIXME/TODO: In the future we should handle mounting here. */
 
2039
        }
 
2040
        else
 
2041
        {
 
2042
            path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
 
2043
        }
 
2044
        fm_main_window_add_new_tab( FM_MAIN_WINDOW( main_window ), path,
 
2045
                                    app_settings.show_side_pane, app_settings.side_pane_mode );
 
2046
 
 
2047
        g_free( path );
 
2048
        folders = folders->next;
 
2049
    }
 
2050
}
 
2051
 
 
2052
GCompareDataFunc get_sort_func( DesktopWindow* win )
 
2053
{
 
2054
    GCompareDataFunc comp;
 
2055
 
 
2056
    switch( win->sort_by )
 
2057
    {
 
2058
        case DW_SORT_BY_NAME:
 
2059
            comp = comp_item_by_name;
 
2060
            break;
 
2061
        case DW_SORT_BY_SIZE:
 
2062
            comp = comp_item_by_size;
 
2063
            break;
 
2064
        case DW_SORT_BY_TYPE:
 
2065
            comp = comp_item_by_type;
 
2066
            break;
 
2067
        case DW_SORT_BY_MTIME:
 
2068
            comp = comp_item_by_mtime;
 
2069
            break;
 
2070
        case DW_SORT_CUSTOM:
 
2071
            comp = comp_item_custom;
 
2072
            break;
 
2073
        default:
 
2074
            comp = comp_item_by_name;
 
2075
            return;
 
2076
    }
 
2077
    return comp;
 
2078
}
 
2079
 
 
2080
/* return -1 if item1 is virtual, and item2 is not, and vice versa. return 0 if both are, or both aren't. */
 
2081
#define COMP_VIRTUAL( item1, item2 )  \
 
2082
  ( ( ((item2->fi->flags & VFS_FILE_INFO_VIRTUAL) ? 1 : 0) - ((item1->fi->flags & VFS_FILE_INFO_VIRTUAL) ? 1 : 0) ) )
 
2083
 
 
2084
int comp_item_by_name( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
 
2085
{
 
2086
    int ret;
 
2087
    if( ret = COMP_VIRTUAL( item1, item2 ) )
 
2088
        return ret;
 
2089
    ret =g_utf8_collate( item1->fi->disp_name, item2->fi->disp_name );
 
2090
    if( win->sort_type == GTK_SORT_DESCENDING )
 
2091
        ret = -ret;
 
2092
    return ret;
 
2093
}
 
2094
 
 
2095
int comp_item_by_size( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win  )
 
2096
{
 
2097
    int ret;
 
2098
    if( ret = COMP_VIRTUAL( item1, item2 ) )
 
2099
        return ret;
 
2100
    ret =item1->fi->size - item2->fi->size;
 
2101
    if( win->sort_type == GTK_SORT_DESCENDING )
 
2102
        ret = -ret;
 
2103
    return ret;
 
2104
}
 
2105
 
 
2106
int comp_item_by_mtime( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win  )
 
2107
{
 
2108
    int ret;
 
2109
    if( ret = COMP_VIRTUAL( item1, item2 ) )
 
2110
        return ret;
 
2111
    ret =item1->fi->mtime - item2->fi->mtime;
 
2112
    if( win->sort_type == GTK_SORT_DESCENDING )
 
2113
        ret = -ret;
 
2114
    return ret;
 
2115
}
 
2116
 
 
2117
int comp_item_by_type( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win  )
 
2118
{
 
2119
    int ret;
 
2120
    if( ret = COMP_VIRTUAL( item1, item2 ) )
 
2121
        return ret;
 
2122
    ret = strcmp( item1->fi->mime_type->type, item2->fi->mime_type->type );
 
2123
 
 
2124
    if( win->sort_type == GTK_SORT_DESCENDING )
 
2125
        ret = -ret;
 
2126
    return ret;
 
2127
}
 
2128
 
 
2129
int comp_item_custom( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
 
2130
{
 
2131
    return (item1->order - item2->order);
 
2132
}
 
2133
 
 
2134
void redraw_item( DesktopWindow* win, DesktopItem* item )
 
2135
{
 
2136
    GdkRectangle rect = item->box;
 
2137
    --rect.x;
 
2138
    --rect.y;
 
2139
    rect.width += 2;
 
2140
    rect.height += 2;
 
2141
    gdk_window_invalidate_rect( ((GtkWidget*)win)->window, &rect, FALSE );
 
2142
}
 
2143
 
 
2144
 
 
2145
/* ----------------- public APIs ------------------*/
 
2146
 
 
2147
void desktop_window_sort_items( DesktopWindow* win, DWSortType sort_by, GtkSortType sort_type )
 
2148
{
 
2149
    GList* items;
 
2150
    GList* special_items;
 
2151
 
 
2152
    if( win->sort_type == sort_type && win->sort_by == sort_by )
 
2153
        return;
 
2154
 
 
2155
    app_settings.desktop_sort_by = win->sort_by = sort_by;
 
2156
    app_settings.desktop_sort_type = win->sort_type = sort_type;
 
2157
 
 
2158
    /* skip the special items since they always appears first */
 
2159
    special_items = win->items;
 
2160
    for( items = special_items; items; items = items->next )
 
2161
    {
 
2162
        DesktopItem* item = (DesktopItem*)items->data;
 
2163
        if( ! (item->fi->flags & VFS_FILE_INFO_VIRTUAL) )
 
2164
            break;
 
2165
    }
 
2166
 
 
2167
    if( ! items )
 
2168
        return;
 
2169
 
 
2170
    /* the previous item of the first non-special item is the last special item */
 
2171
    if( items->prev )
 
2172
    {
 
2173
        items->prev->next = NULL;
 
2174
        items->prev = NULL;
 
2175
    }
 
2176
 
 
2177
    items = g_list_sort_with_data( items, get_sort_func(win), win );
 
2178
    win->items = g_list_concat( special_items, items );
 
2179
 
 
2180
    layout_items( win );
 
2181
}
 
2182
 
 
2183
GList* desktop_window_get_selected_items( DesktopWindow* win )
 
2184
{
 
2185
    GList* sel = NULL;
 
2186
    GList* l;
 
2187
 
 
2188
    for( l = win->items; l; l = l->next )
 
2189
    {
 
2190
        DesktopItem* item = (DesktopItem*) l->data;
 
2191
        if( item->is_selected )
 
2192
        {
 
2193
            if( G_UNLIKELY( item == win->focus ) )
 
2194
                sel = g_list_prepend( sel, item );
 
2195
            else
 
2196
                sel = g_list_append( sel, item );
 
2197
        }
 
2198
    }
 
2199
 
 
2200
    return sel;
 
2201
}
 
2202
 
 
2203
GList* desktop_window_get_selected_files( DesktopWindow* win )
 
2204
{
 
2205
    GList* sel = desktop_window_get_selected_items( win );
 
2206
    GList* l;
 
2207
 
 
2208
    l = sel;
 
2209
    while( l )
 
2210
    {
 
2211
        DesktopItem* item = (DesktopItem*) l->data;
 
2212
        if( item->fi->flags & VFS_FILE_INFO_VIRTUAL )
 
2213
        {
 
2214
            /* don't include virtual items */
 
2215
            GList* tmp = l;
 
2216
            l = tmp->next;
 
2217
            sel = g_list_remove_link( sel, tmp );
 
2218
            g_list_free1( tmp );
 
2219
        }
 
2220
        else
 
2221
        {
 
2222
            l->data = vfs_file_info_ref( item->fi );
 
2223
            l = l->next;
 
2224
        }
 
2225
    }
 
2226
    return sel;
 
2227
}
 
2228
 
 
2229
 
 
2230
/*----------------- X11-related sutff ----------------*/
 
2231
 
 
2232
static
 
2233
GdkFilterReturn on_rootwin_event ( GdkXEvent *xevent,
 
2234
                                   GdkEvent *event,
 
2235
                                   gpointer data )
 
2236
{
 
2237
    XPropertyEvent * evt = ( XPropertyEvent* ) xevent;
 
2238
    DesktopWindow* self = (DesktopWindow*)data;
 
2239
 
 
2240
    if ( evt->type == PropertyNotify )
 
2241
    {
 
2242
        if( evt->atom == ATOM_NET_WORKAREA )
 
2243
        {
 
2244
            /* working area is resized */
 
2245
            get_working_area( gtk_widget_get_screen((GtkWidget*)self), &self->wa );
 
2246
            layout_items( self );
 
2247
        }
 
2248
#if 0
 
2249
        else if( evt->atom == ATOM_XROOTMAP_ID )
 
2250
        {
 
2251
            /* wallpaper was changed by other programs */
 
2252
        }
 
2253
#endif
 
2254
    }
 
2255
    return GDK_FILTER_TRANSLATE;
 
2256
}
 
2257
 
 
2258
/* This function is taken from xfdesktop */
 
2259
void forward_event_to_rootwin( GdkScreen *gscreen, GdkEvent *event )
 
2260
{
 
2261
    XButtonEvent xev, xev2;
 
2262
    Display *dpy = GDK_DISPLAY_XDISPLAY( gdk_screen_get_display( gscreen ) );
 
2263
 
 
2264
    if ( event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE )
 
2265
    {
 
2266
        if ( event->type == GDK_BUTTON_PRESS )
 
2267
        {
 
2268
            xev.type = ButtonPress;
 
2269
            /*
 
2270
             * rox has an option to disable the next
 
2271
             * instruction. it is called "blackbox_hack". Does
 
2272
             * anyone know why exactly it is needed?
 
2273
             */
 
2274
            XUngrabPointer( dpy, event->button.time );
 
2275
        }
 
2276
        else
 
2277
            xev.type = ButtonRelease;
 
2278
 
 
2279
        xev.button = event->button.button;
 
2280
        xev.x = event->button.x;    /* Needed for icewm */
 
2281
        xev.y = event->button.y;
 
2282
        xev.x_root = event->button.x_root;
 
2283
        xev.y_root = event->button.y_root;
 
2284
        xev.state = event->button.state;
 
2285
 
 
2286
        xev2.type = 0;
 
2287
    }
 
2288
    else if ( event->type == GDK_SCROLL )
 
2289
    {
 
2290
        xev.type = ButtonPress;
 
2291
        xev.button = event->scroll.direction + 4;
 
2292
        xev.x = event->scroll.x;    /* Needed for icewm */
 
2293
        xev.y = event->scroll.y;
 
2294
        xev.x_root = event->scroll.x_root;
 
2295
        xev.y_root = event->scroll.y_root;
 
2296
        xev.state = event->scroll.state;
 
2297
 
 
2298
        xev2.type = ButtonRelease;
 
2299
        xev2.button = xev.button;
 
2300
    }
 
2301
    else
 
2302
        return ;
 
2303
    xev.window = GDK_WINDOW_XWINDOW( gdk_screen_get_root_window( gscreen ) );
 
2304
    xev.root = xev.window;
 
2305
    xev.subwindow = None;
 
2306
    xev.time = event->button.time;
 
2307
    xev.same_screen = True;
 
2308
 
 
2309
    XSendEvent( dpy, xev.window, False, ButtonPressMask | ButtonReleaseMask,
 
2310
                ( XEvent * ) & xev );
 
2311
    if ( xev2.type == 0 )
 
2312
        return ;
 
2313
 
 
2314
    /* send button release for scroll event */
 
2315
    xev2.window = xev.window;
 
2316
    xev2.root = xev.root;
 
2317
    xev2.subwindow = xev.subwindow;
 
2318
    xev2.time = xev.time;
 
2319
    xev2.x = xev.x;
 
2320
    xev2.y = xev.y;
 
2321
    xev2.x_root = xev.x_root;
 
2322
    xev2.y_root = xev.y_root;
 
2323
    xev2.state = xev.state;
 
2324
    xev2.same_screen = xev.same_screen;
 
2325
 
 
2326
    XSendEvent( dpy, xev2.window, False, ButtonPressMask | ButtonReleaseMask,
 
2327
                ( XEvent * ) & xev2 );
 
2328
}
 
2329
 
 
2330
#if 0
 
2331
GdkPixmap* get_root_pixmap( GdkWindow* root )
 
2332
{
 
2333
    Pixmap root_pix = None;
 
2334
 
 
2335
    Atom type;
 
2336
    int format;
 
2337
    long bytes_after;
 
2338
    Pixmap *data = NULL;
 
2339
    long n_items;
 
2340
    int result;
 
2341
 
 
2342
    result =  XGetWindowProperty(
 
2343
                            GDK_WINDOW_XDISPLAY( root ),
 
2344
                            GDK_WINDOW_XID( root ),
 
2345
                            ATOM_XROOTMAP_ID,
 
2346
                            0, 16L,
 
2347
                            False, XA_PIXMAP,
 
2348
                            &type, &format, &n_items,
 
2349
                            &bytes_after, (unsigned char **)&data);
 
2350
 
 
2351
    if (result == Success && n_items)
 
2352
        root_pix = *data;
 
2353
 
 
2354
    if (data)
 
2355
        XFree(data);
 
2356
 
 
2357
    return root_pix ? gdk_pixmap_foreign_new( root_pix ) : NULL;
 
2358
}
 
2359
 
 
2360
gboolean set_root_pixmap(  GdkWindow* root, GdkPixmap* pix )
 
2361
{
 
2362
    return TRUE;
 
2363
}
 
2364
 
 
2365
#endif