4
* Copyright 2008 PCMan <pcman.tw@gmail.com>
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.
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.
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,
22
#include <glib/gi18n.h>
24
#include "desktop-window.h"
25
#include "vfs-file-info.h"
26
#include "vfs-mime-type.h"
29
#include "working-area.h"
31
#include "ptk-file-misc.h"
32
#include "ptk-file-menu.h"
33
#include "ptk-file-task.h"
34
#include "ptk-utils.h"
37
#include "main-window.h"
38
#include "pref-dialog.h"
39
#include "ptk-file-browser.h"
42
#include <X11/Xatom.h>
44
#include <gdk/gdkkeysyms.h>
47
#include <sys/types.h>
55
GdkRectangle box; /* bounding rect */
56
GdkRectangle icon_rect;
57
GdkRectangle text_rect;
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 */
65
gboolean is_selected : 1;
66
gboolean is_prelight : 1;
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);
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 ); */
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 );
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 );
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 );
108
static void on_paste( GtkMenuItem *menuitem, DesktopWindow* self );
109
static void on_settings( GtkMenuItem *menuitem, DesktopWindow* self );
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 );
114
static GdkFilterReturn on_rootwin_event ( GdkXEvent *xevent, GdkEvent *event, gpointer data );
115
static void forward_event_to_rootwin( GdkScreen *gscreen, GdkEvent *event );
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 );
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 );
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 );
135
static void redraw_item( DesktopWindow* win, DesktopItem* item );
136
static void desktop_item_free( DesktopItem* item );
139
static GdkPixmap* get_root_pixmap( GdkWindow* root );
140
static gboolean set_root_pixmap( GdkWindow* root , GdkPixmap* pix );
143
static DesktopItem* hit_test( DesktopWindow* self, int x, int y );
145
/* static Atom ATOM_XROOTMAP_ID = 0; */
146
static Atom ATOM_NET_WORKAREA = 0;
149
static GtkWindowClass *parent_class = NULL;
151
static GdkPixmap* pix = NULL;
154
DRAG_TARGET_URI_LIST,
155
DRAG_TARGET_DESKTOP_ICON
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 }
164
static GdkAtom text_uri_list_atom = 0;
165
static GdkAtom desktop_icon_atom = 0;
167
static PtkMenuItemEntry icon_menu[] =
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 ),
180
static PtkMenuItemEntry create_new_menu[] =
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 ),
187
static PtkMenuItemEntry desktop_menu[] =
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 ),
198
GType desktop_window_get_type(void)
200
static GType self_type = 0;
203
static const GTypeInfo self_info =
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),
213
(GInstanceInitFunc)desktop_window_init,
214
NULL /* value_table */
217
self_type = g_type_register_static(GTK_TYPE_WINDOW, "DesktopWindow", &self_info, 0); }
222
static void desktop_window_class_init(DesktopWindowClass *klass)
224
GObjectClass *g_object_class;
226
typedef gboolean (*DeleteEvtHandler) (GtkWidget*, GdkEvent*);
228
g_object_class = G_OBJECT_CLASS(klass);
229
wc = GTK_WIDGET_CLASS(klass);
231
g_object_class->finalize = desktop_window_finalize;
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;
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;
255
parent_class = (GtkWindowClass*)g_type_class_peek(GTK_TYPE_WINDOW);
257
/* ATOM_XROOTMAP_ID = XInternAtom( GDK_DISPLAY(),"_XROOTMAP_ID", False ); */
258
ATOM_NET_WORKAREA = XInternAtom( GDK_DISPLAY(),"_NET_WORKAREA", False );
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 );
264
static void desktop_window_init(DesktopWindow *self)
267
PangoFontMetrics *metrics;
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;
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);
282
g_object_ref( self->icon_render );
283
gtk_object_sink(self->icon_render);
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 );
291
metrics = pango_context_get_metrics(
292
pc, ((GtkWidget*)self)->style->font_desc,
293
pango_context_get_language(pc));
295
font_h = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent (metrics);
296
font_h /= PANGO_SCALE;
299
self->icon_size = 48;
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 );
315
GTK_WIDGET_SET_FLAGS( (GtkWidget*)self, GTK_CAN_FOCUS );
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 |
324
GDK_PROPERTY_CHANGE_MASK );
326
gtk_drag_dest_set( (GtkWidget*)self, 0, NULL, 0,
327
GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK );
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 );
336
GtkWidget* desktop_window_new(void)
338
GtkWindow* w = (GtkWindow*)g_object_new(DESKTOP_WINDOW_TYPE, NULL);
339
w->type = GTK_WINDOW_TOPLEVEL;
340
return (GtkWidget*)w;
343
void desktop_item_free( DesktopItem* item )
345
vfs_file_info_unref( item->fi );
346
g_slice_free( DesktopItem, item );
349
void desktop_window_finalize(GObject *object)
351
DesktopWindow *self = (DesktopWindow*)object;
353
g_return_if_fail(object != NULL);
354
g_return_if_fail(IS_DESKTOP_WINDOW(object));
356
gdk_window_remove_filter(
357
gdk_screen_get_root_window( gtk_widget_get_screen( (GtkWidget*)object) ),
358
on_rootwin_event, self );
360
if( self->background )
361
g_object_unref( self->background );
363
self = DESKTOP_WINDOW(object);
364
g_object_unref( self->dir );
366
g_list_foreach( self->items, (GFunc)desktop_item_free, NULL );
367
g_list_free( self->items );
369
if (G_OBJECT_CLASS(parent_class)->finalize)
370
(* G_OBJECT_CLASS(parent_class)->finalize)(object);
373
/*--------------- Signal handlers --------------*/
375
gboolean on_expose( GtkWidget* w, GdkEventExpose* evt )
377
DesktopWindow* self = (DesktopWindow*)w;
379
GdkRectangle intersect;
381
if( G_UNLIKELY( ! GTK_WIDGET_VISIBLE (w) || ! GTK_WIDGET_MAPPED (w) ) )
384
gdk_draw_drawable( w->window, self->gc,
386
evt->area.x, evt->area.y,
387
evt->area.x, evt->area.y,
388
evt->area.width, evt->area.height );
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 );
398
if( self->rubber_bending )
399
paint_rubber_banding_rect( self );
401
for( l = self->items; l; l = l->next )
403
DesktopItem* item = (DesktopItem*)l->data;
404
if( gdk_rectangle_intersect( &evt->area, &item->box, &intersect ) )
405
paint_item( self, item, &intersect );
410
void on_size_allocate( GtkWidget* w, GtkAllocation* alloc )
413
DesktopWindow* self = (DesktopWindow*)w;
416
get_working_area( gtk_widget_get_screen(w), &self->wa );
419
GTK_WIDGET_CLASS(parent_class)->size_allocate( w, alloc );
422
void desktop_window_set_pixmap( DesktopWindow* win, GdkPixmap* pix )
424
if( win->background )
425
g_object_unref( win->background );
426
win->background = pix ? g_object_ref( pix ) : NULL;
428
if( GTK_WIDGET_REALIZED( win ) )
429
gdk_window_set_back_pixmap( ((GtkWidget*)win)->window, win->background, FALSE );
432
void desktop_window_set_bg_color( DesktopWindow* win, GdkColor* clr )
437
gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
439
if( GTK_WIDGET_VISIBLE(win) )
440
gtk_widget_queue_draw( (GtkWidget*)win );
444
void desktop_window_set_text_color( DesktopWindow* win, GdkColor* clr, GdkColor* shadow )
451
gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
456
win->shadow = *shadow;
457
gdk_rgb_find_color( gtk_widget_get_colormap( (GtkWidget*)win ),
460
if( GTK_WIDGET_VISIBLE(win) )
461
gtk_widget_queue_draw( (GtkWidget*)win );
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.
471
void desktop_window_set_background( DesktopWindow* win, GdkPixbuf* src_pix, DWBgType type )
473
GdkPixmap* pixmap = NULL;
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;
488
if( type == DW_BG_TILE )
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 );
495
int src_x = 0, src_y = 0;
496
int dest_x = 0, dest_y = 0;
499
pixmap = gdk_pixmap_new( ((GtkWidget*)win)->window, dest_w, dest_h, -1 );
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 );
506
scaled = gdk_pixbuf_scale_simple( src_pix, dest_w, dest_h, GDK_INTERP_BILINEAR );
511
if( src_w == dest_w && src_h == dest_h )
512
scaled = (GdkPixbuf*)g_object_ref( src_pix );
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 );
519
scaled = (GdkPixbuf*)g_object_ref( src_pix );
521
scaled = gdk_pixbuf_scale_simple( src_pix, (src_w * ratio), (src_h * ratio), GDK_INTERP_BILINEAR );
523
w = gdk_pixbuf_get_width( scaled );
524
h = gdk_pixbuf_get_height( scaled );
527
src_x = (w - dest_w) / 2;
528
else if( w < dest_w )
529
dest_x = (dest_w - w) / 2;
532
src_y = (h - dest_h) / 2;
533
else if( h < dest_h )
534
dest_y = (dest_h - h) / 2;
536
case DW_BG_CENTER: /* no scale is needed */
537
scaled = (GdkPixbuf*)g_object_ref( src_pix );
542
src_x = (src_w - dest_w) / 2;
547
dest_x = (dest_w - src_w) / 2;
552
src_y = (src_h - dest_h) / 2;
557
dest_y = (dest_h - src_h) / 2;
564
if( w != dest_w || h != dest_h )
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 );
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 );
578
g_object_unref( pixmap );
584
if( win->background )
585
g_object_unref( win->background );
586
win->background = pixmap;
589
gdk_window_set_back_pixmap( ((GtkWidget*)win)->window, pixmap, FALSE );
591
gdk_window_set_background( ((GtkWidget*)win)->window, &win->bg );
593
gdk_window_clear( ((GtkWidget*)win)->window );
594
gtk_widget_queue_draw( (GtkWidget*)win );
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 ) );
600
XGrabServer (xdisplay);
604
xpixmap = GDK_WINDOW_XWINDOW(pixmap);
606
XChangeProperty( xdisplay,
608
gdk_x11_get_xatom_by_name("_XROOTPMAP_ID"), XA_PIXMAP,
610
(guchar *) &xpixmap, 1);
612
XSetWindowBackgroundPixmap( xdisplay, xroot, xpixmap );
616
/* FIXME: Anyone knows how to handle this correctly??? */
618
XClearWindow( xdisplay, xroot );
620
XUngrabServer( xdisplay );
624
void desktop_window_set_icon_size( DesktopWindow* win, int size )
627
win->icon_size = size;
629
for( l = win->items; l; l = l->next )
631
VFSFileInfo* fi = ((DesktopItem*)l->data)->fi;
633
/* reload the icons for special items if needed */
634
if( (fi->flags & VFS_FILE_INFO_DESKTOP_ENTRY) && ! fi->big_thumbnail)
636
path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
637
vfs_file_info_load_special_info( fi, path );
640
else if(fi->flags & VFS_FILE_INFO_VIRTUAL)
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 );
649
else if( vfs_file_info_is_image( fi ) && ! fi->big_thumbnail )
651
vfs_thumbnail_loader_request( win->dir, fi, TRUE );
656
void desktop_window_reload_icons( DesktopWindow* win )
660
for( l = win->items; l; l = l->next )
662
DesktopItem* item = (DesktopItem*)l->data;
665
g_object_unref( item->icon );
668
item->icon = vfs_file_info_get_big_icon( item->fi );
678
void on_size_request( GtkWidget* w, GtkRequisition* req )
680
GdkScreen* scr = gtk_widget_get_screen( w );
681
req->width = gdk_screen_get_width( scr );
682
req->height = gdk_screen_get_height( scr );
685
static void calc_rubber_banding_rect( DesktopWindow* self, int x, int y, GdkRectangle* rect )
687
int x1, x2, y1, y2, w, h;
688
if( self->drag_start_x < x )
690
x1 = self->drag_start_x;
696
x2 = self->drag_start_x;
699
if( self->drag_start_y < y )
701
y1 = self->drag_start_y;
707
y2 = self->drag_start_y;
712
rect->width = x2 - x1;
713
rect->height = y2 - y1;
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
723
static void colorize_pixbuf( GdkPixbuf* pix, GdkColor* clr, guint alpha )
726
int x, y, width, height, rowstride;
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;
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);
739
for (y = 0; y < height; y++)
742
for (x = 0; x < width; x++)
744
p[0] = p[0] * r / 255;
745
p[1] = p[1] * g / 255;
746
p[2] = p[2] * b / 255;
749
p[3] = p[3] * a / 255;
759
void paint_rubber_banding_rect( DesktopWindow* self )
761
int x1, x2, y1, y2, w, h, pattern_w, pattern_h;
768
calc_rubber_banding_rect( self, self->rubber_bending_x, self->rubber_bending_y, &rect );
770
if( rect.width <= 0 || rect.height <= 0 )
773
gtk_widget_style_get( GTK_WIDGET(self),
774
"selection-box-color", &clr,
775
"selection-box-alpha", &alpha,
779
gc = gdk_gc_new( ((GtkWidget*)self)->window);
780
clr = gdk_color_copy (>K_WIDGET (self)->style->base[GTK_STATE_SELECTED]);
781
alpha = 64; /* FIXME: should be themable in the future */
784
if( self->bg_type == DW_BG_TILE )
786
/* FIXME: disable background in tile mode because current implementation is too slow */
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 );
793
else if( self->bg_type != DW_BG_COLOR )
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 );
802
colorize_pixbuf( pix, clr, alpha );
803
if( self->bg_type == DW_BG_TILE )
806
/* FIXME: This is damn slow!! */
807
pattern = gdk_pixmap_new( ((GtkWidget*)self)->window, pattern_w, pattern_h, -1 );
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 );
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 );
825
g_object_unref( pix );
827
else if( self->bg_type == DW_BG_COLOR ) /* draw background color */
829
GdkColor clr2 = self->bg;
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 );
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 );
845
gdk_color_free (clr);
846
gdk_gc_destroy( gc );
849
static void update_rubberbanding( DesktopWindow* self, int newx, int newy )
852
GdkRectangle old_rect, new_rect;
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 );
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 );
862
region = gdk_region_rectangle( &old_rect );
863
gdk_region_union_with_rect( region, &new_rect );
865
// gdk_window_invalidate_region( ((GtkWidget*)self)->window, ®ion, TRUE );
867
gdk_region_destroy( region );
869
self->rubber_bending_x = newx;
870
self->rubber_bending_y = newy;
872
/* update selection */
873
for( l = self->items; l; l = l->next )
875
DesktopItem* item = (DesktopItem*)l->data;
877
if( gdk_rectangle_intersect( &new_rect, &item->icon_rect, NULL ) ||
878
gdk_rectangle_intersect( &new_rect, &item->text_rect, NULL ) )
883
if( item->is_selected != selected )
885
item->is_selected = selected;
886
redraw_item( self, item );
891
gboolean on_button_press( GtkWidget* w, GdkEventButton* evt )
893
DesktopWindow* self = (DesktopWindow*)w;
894
DesktopItem *item, *clicked_item = NULL;
897
clicked_item = hit_test( w, (int)evt->x, (int)evt->y );
899
if( evt->type == GDK_BUTTON_PRESS )
901
if( evt->button == 1 ) /* left button */
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;
908
/* if ctrl / shift is not pressed, deselect all. */
909
if( ! (evt->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
911
/* don't cancel selection if clicking on selected items */
912
if( !( (evt->button == 1 || evt->button == 3) && clicked_item && clicked_item->is_selected) )
914
for( l = self->items; l ;l = l->next )
916
item = (DesktopItem*) l->data;
917
if( item->is_selected )
919
item->is_selected = FALSE;
920
redraw_item( self, item );
928
if( evt->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK) )
929
clicked_item->is_selected = ! clicked_item->is_selected;
931
clicked_item->is_selected = TRUE;
933
if( self->focus && self->focus != item )
935
DesktopItem* old_focus = self->focus;
937
redraw_item( w, old_focus );
939
self->focus = clicked_item;
940
redraw_item( self, clicked_item );
942
if( evt->button == 3 ) /* right click */
944
GList* sel = desktop_window_get_selected_items( self );
947
item = (DesktopItem*)sel->data;
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 );
957
gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
962
else /* no item is clicked */
964
if( evt->button == 3 ) /* right click on the blank area */
966
if( ! app_settings.show_wm_menu ) /* if our desktop menu is used */
968
GtkWidget *popup, *sort_by_items[ 4 ], *sort_type_items[ 2 ];
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 );
981
gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
982
goto out; /* don't forward the event to root win */
985
else if( evt->button == 1 )
987
self->rubber_bending = TRUE;
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 ); */
994
self->rubber_bending_x = evt->x;
995
self->rubber_bending_y = evt->y;
1000
else if( evt->type == GDK_2BUTTON_PRESS )
1002
if( clicked_item && evt->button == 1) /* left double click */
1004
if( vfs_file_info_is_dir( clicked_item->fi ) ) /* this is a folder */
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 );
1011
else /* regular files */
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 );
1021
/* forward the event to root window */
1022
forward_event_to_rootwin( gtk_widget_get_screen(w), evt );
1025
if( ! GTK_WIDGET_HAS_FOCUS(w) )
1027
/* g_debug( "we don't have the focus, grab it!" ); */
1028
gtk_widget_grab_focus( w );
1033
gboolean on_button_release( GtkWidget* w, GdkEventButton* evt )
1035
DesktopWindow* self = (DesktopWindow*)w;
1037
self->button_pressed = FALSE;
1039
if( self->rubber_bending )
1041
update_rubberbanding( self, evt->x, evt->y );
1042
gtk_grab_remove( w );
1043
self->rubber_bending = FALSE;
1045
else if( self->dragging )
1047
self->dragging = FALSE;
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 );
1057
gboolean on_mouse_move( GtkWidget* w, GdkEventMotion* evt )
1059
DesktopWindow* self = (DesktopWindow*)w;
1061
if( ! self->button_pressed )
1064
if( self->dragging )
1067
else if( self->rubber_bending )
1069
update_rubberbanding( self, evt->x, evt->y );
1073
if ( gtk_drag_check_threshold( w,
1078
GtkTargetList* target_list;
1079
gboolean virtual_item = FALSE;
1080
GList* sels = desktop_window_get_selected_items(self);
1082
self->dragging = TRUE;
1083
if( sels && sels->next == NULL ) /* only one item selected */
1085
DesktopItem* item = (DesktopItem*)sels->data;
1086
if( item->fi->flags & VFS_FILE_INFO_VIRTUAL )
1087
virtual_item = TRUE;
1089
g_list_free( sels );
1091
target_list = gtk_target_list_new( drag_targets + 1, G_N_ELEMENTS(drag_targets) - 1 );
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,
1097
gtk_target_list_unref( target_list );
1104
void on_drag_begin( GtkWidget* w, GdkDragContext* ctx )
1106
DesktopWindow* self = (DesktopWindow*)w;
1109
static GdkAtom get_best_target_at_dest( DesktopWindow* self, GdkDragContext* ctx, gint x, gint y )
1112
GdkAtom expected_target = 0;
1114
if( G_LIKELY(ctx->targets) )
1116
if( ctx->action != GDK_ACTION_MOVE )
1117
expected_target = text_uri_list_atom;
1120
item = hit_test( self, x, y );
1121
if( item ) /* drag over a desktpo item */
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;
1129
expected_target = text_uri_list_atom;
1130
g_list_free( sels );
1132
else /* drag over blank area, check if it's a desktop icon first. */
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;
1139
if( g_list_find( ctx->targets, GUINT_TO_POINTER(expected_target) ) )
1140
return expected_target;
1145
#define GDK_ACTION_ALL (GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK)
1147
gboolean on_drag_motion( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time )
1149
DesktopWindow* self = (DesktopWindow*)w;
1153
if( ! self->drag_entered )
1155
self->drag_entered = TRUE;
1158
if( self->rubber_bending )
1160
/* g_debug("rubber banding!"); */
1164
/* g_debug( "suggest: %d, action = %d", ctx->suggested_action, ctx->action ); */
1166
if( g_list_find( ctx->targets, GUINT_TO_POINTER(text_uri_list_atom) ) )
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. */
1181
if( get_best_target_at_dest(self, ctx, x, y ) == text_uri_list_atom )
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 );
1188
else /* move desktop icon */
1190
suggested_action = GDK_ACTION_MOVE;
1193
ctx->action = suggested_action;
1194
gdk_drag_status( ctx, suggested_action, time );
1196
else if( g_list_find( ctx->targets, GUINT_TO_POINTER(desktop_icon_atom) ) ) /* moving desktop icon */
1198
ctx->action = GDK_ACTION_MOVE;
1199
gdk_drag_status( ctx, GDK_ACTION_MOVE, time );
1203
gdk_drag_status (ctx, 0, time);
1208
gboolean on_drag_drop( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, guint time )
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 )
1215
if( target == text_uri_list_atom || target == desktop_icon_atom )
1216
gtk_drag_get_data( w, ctx, target, time );
1220
void on_drag_data_get( GtkWidget* w, GdkDragContext* ctx, GtkSelectionData* data, guint info, guint time )
1222
DesktopWindow* self = (DesktopWindow*)w;
1227
if( info == DRAG_TARGET_URI_LIST )
1229
GString *buf = g_string_sized_new( 4096 );
1231
sels = desktop_window_get_selected_files( self );
1233
for( l = sels; l; l = l->next )
1235
VFSFileInfo* fi = (VFSFileInfo*)l->data;
1238
if( fi->flags & VFS_FILE_INFO_VIRTUAL )
1241
path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
1242
uri = g_filename_to_uri( path, NULL, NULL );
1244
g_string_append( buf, uri );
1245
g_string_append( buf, "\r\n" );
1249
g_list_foreach( sels, vfs_file_info_unref, NULL );
1250
g_list_free( sels );
1252
uri_list = g_convert( buf->str, buf->len, "ASCII", "UTF-8", NULL, &len, NULL);
1253
g_string_free( buf, TRUE);
1257
gtk_selection_data_set( data,
1259
8, (guchar *)uri_list, len );
1263
else if( info == DRAG_TARGET_DESKTOP_ICON )
1268
static char** get_files_from_selection_data(GtkSelectionData* data)
1270
char** files = gtk_selection_data_get_uris(data), **pfile;
1273
/* convert uris to filenames */
1274
for( pfile = files; *pfile; ++pfile )
1276
char* file = g_filename_from_uri( *pfile, NULL, NULL );
1284
void on_drag_data_received( GtkWidget* w, GdkDragContext* ctx, gint x, gint y, GtkSelectionData* data, guint info, guint time )
1286
DesktopWindow* self = (DesktopWindow*)w;
1288
if( data->target == text_uri_list_atom )
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;
1298
if( (data->length < 0) || (data->format != 8) )
1300
gtk_drag_finish( ctx, FALSE, FALSE, time );
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 );
1310
/* We are just checking the suggested actions for the drop site, not really drop */
1311
if( self->pending_drop_action )
1313
GdkDragAction suggested_action = 0;
1315
struct stat statbuf;
1317
if( stat( dest_dir ? dest_dir : vfs_get_desktop_dir(), &statbuf ) == 0 )
1319
dest_dev = statbuf.st_dev;
1320
if( 0 == self->drag_src_dev )
1323
files = get_files_from_selection_data(data);
1324
self->drag_src_dev = dest_dev;
1327
for( pfile = files; *pfile; ++pfile )
1329
if( stat( *pfile, &statbuf ) == 0 && statbuf.st_dev != dest_dev )
1331
self->drag_src_dev = statbuf.st_dev;
1336
g_strfreev( files );
1339
if( self->drag_src_dev != dest_dev ) /* src and dest are on different devices */
1340
suggested_action = GDK_ACTION_COPY;
1342
suggested_action = GDK_ACTION_MOVE;
1345
self->pending_drop_action = FALSE;
1346
gdk_drag_status( ctx, suggested_action, time );
1350
switch ( ctx->action )
1352
case GDK_ACTION_COPY:
1353
file_action = VFS_FILE_TASK_COPY;
1355
case GDK_ACTION_LINK:
1356
file_action = VFS_FILE_TASK_LINK;
1359
GDK_ACTION_DEFAULT, GDK_ACTION_PRIVATE, and GDK_ACTION_ASK are not handled */
1364
files = get_files_from_selection_data( data );
1365
/* g_debug("file_atcion: %d", file_action); */
1367
n = g_strv_length( files );
1368
for( i = 0; i < n; ++i )
1369
file_list = g_list_prepend( file_list, files[i] );
1372
task = ptk_file_task_new( file_action,
1374
dest_dir ? dest_dir : vfs_get_desktop_dir(),
1375
GTK_WINDOW( self ) );
1376
ptk_file_task_run( task );
1380
gtk_drag_finish( ctx, TRUE, FALSE, time );
1382
else if( data->target == desktop_icon_atom ) /* moving desktop icon */
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 )
1389
DesktopItem* item = l->data;
1390
#if 0 /* temporarily turn off */
1391
move_item( self, item, x_off, y_off, TRUE );
1393
/* g_debug( "move: %d, %d", x_off, y_off ); */
1395
g_list_free( sels );
1396
gtk_drag_finish( ctx, TRUE, FALSE, time );
1400
void on_drag_leave( GtkWidget* w, GdkDragContext* ctx, guint time )
1402
DesktopWindow* self = (DesktopWindow*)w;
1403
self->drag_entered = FALSE;
1404
self->drag_src_dev = 0;
1407
void on_drag_end( GtkWidget* w, GdkDragContext* ctx )
1409
DesktopWindow* self = (DesktopWindow*)w;
1412
gboolean on_key_press( GtkWidget* w, GdkEventKey* evt )
1415
DesktopWindow* self = (DesktopWindow*)w;
1416
int modifier = ( evt->state & ( GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK ) );
1418
sels = desktop_window_get_selected_files( self );
1420
if ( modifier == GDK_CONTROL_MASK )
1422
switch ( evt->keyval )
1426
ptk_clipboard_cut_or_copy_files( vfs_get_desktop_dir(), sels, FALSE );
1430
ptk_clipboard_cut_or_copy_files( vfs_get_desktop_dir(), sels, TRUE );
1433
on_paste( NULL, self );
1437
ptk_file_browser_invert_selection( file_browser );
1440
ptk_file_browser_select_all( file_browser );
1445
else if ( modifier == GDK_MOD1_MASK )
1447
switch ( evt->keyval )
1451
ptk_show_file_properties( NULL, vfs_get_desktop_dir(), sels );
1455
else if ( modifier == 0 )
1457
switch ( evt->keyval )
1461
ptk_rename_file( NULL, vfs_get_desktop_dir(), (VFSFileInfo*)sels->data );
1465
ptk_delete_files( NULL, vfs_get_desktop_dir(), sels );
1471
vfs_file_info_list_free( sels );
1476
void on_style_set( GtkWidget* w, GtkStyle* prev )
1478
DesktopWindow* self = (DesktopWindow*)w;
1481
PangoFontMetrics *metrics;
1483
pc = gtk_widget_get_pango_context( (GtkWidget*)self );
1485
metrics = pango_context_get_metrics(
1486
pc, ((GtkWidget*)self)->style->font_desc,
1487
pango_context_get_language(pc));
1489
font_h = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent (metrics);
1490
font_h /= PANGO_SCALE;
1493
void on_realize( GtkWidget* w )
1496
DesktopWindow* self = (DesktopWindow*)w;
1498
GTK_WIDGET_CLASS(parent_class)->realize( w );
1499
gdk_window_set_type_hint( w->window,
1500
GDK_WINDOW_TYPE_HINT_DESKTOP );
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 );
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);
1514
self->gc = gdk_gc_new( w->window );
1516
// if( self->background )
1517
// gdk_window_set_back_pixmap( w->window, self->background, FALSE );
1520
gboolean on_focus_in( GtkWidget* w, GdkEventFocus* evt )
1522
DesktopWindow* self = (DesktopWindow*) w;
1523
GTK_WIDGET_SET_FLAGS( w, GTK_HAS_FOCUS );
1525
redraw_item( self, self->focus );
1529
gboolean on_focus_out( GtkWidget* w, GdkEventFocus* evt )
1531
DesktopWindow* self = (DesktopWindow*) w;
1534
GTK_WIDGET_UNSET_FLAGS( w, GTK_HAS_FOCUS );
1535
redraw_item( self, self->focus );
1541
gboolean on_scroll( GtkWidget *w, GdkEventScroll *evt, gpointer user_data )
1543
forward_event_to_rootwin( gtk_widget_get_screen( w ), ( GdkEvent* ) evt );
1549
void on_sort_by_name ( GtkMenuItem *menuitem, DesktopWindow* self )
1551
desktop_window_sort_items( self, DW_SORT_BY_NAME, self->sort_type );
1554
void on_sort_by_size ( GtkMenuItem *menuitem, DesktopWindow* self )
1556
desktop_window_sort_items( self, DW_SORT_BY_SIZE, self->sort_type );
1559
void on_sort_by_mtime ( GtkMenuItem *menuitem, DesktopWindow* self )
1561
desktop_window_sort_items( self, DW_SORT_BY_MTIME, self->sort_type );
1564
void on_sort_by_type ( GtkMenuItem *menuitem, DesktopWindow* self )
1566
desktop_window_sort_items( self, DW_SORT_BY_TYPE, self->sort_type );
1569
void on_sort_custom( GtkMenuItem *menuitem, DesktopWindow* self )
1571
desktop_window_sort_items( self, DW_SORT_CUSTOM, self->sort_type );
1574
void on_sort_ascending( GtkMenuItem *menuitem, DesktopWindow* self )
1576
desktop_window_sort_items( self, self->sort_by, GTK_SORT_ASCENDING );
1579
void on_sort_descending( GtkMenuItem *menuitem, DesktopWindow* self )
1581
desktop_window_sort_items( self, self->sort_by, GTK_SORT_DESCENDING );
1584
void on_paste( GtkMenuItem *menuitem, DesktopWindow* self )
1586
const gchar* dest_dir = vfs_get_desktop_dir();
1587
ptk_clipboard_paste_files( NULL, dest_dir );
1591
on_popup_new_folder_activate ( GtkMenuItem *menuitem,
1594
ptk_create_new_file( NULL, vfs_get_desktop_dir(), TRUE, NULL );
1598
on_popup_new_text_file_activate ( GtkMenuItem *menuitem,
1601
ptk_create_new_file( NULL, vfs_get_desktop_dir(), FALSE, NULL );
1604
void on_settings( GtkMenuItem *menuitem, DesktopWindow* self )
1606
fm_edit_preference( NULL, PREF_DESKTOP );
1610
/* private methods */
1612
void calc_item_size( DesktopWindow* self, DesktopItem* item )
1614
PangoLayoutLine* line;
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;
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 );
1626
if( pango_layout_get_line_count(self->pl) >= 2 ) /* there are more than 2 lines */
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.
1633
#if defined (PANGO_VERSION_CHECK)
1634
#if PANGO_VERSION_CHECK( 1, 16, 0 )
1635
line = pango_layout_get_line_readonly( self->pl, 1 );
1637
line = pango_layout_get_line( self->pl, 1 );
1640
line = pango_layout_get_line( self->pl, 1 );
1642
item->len1 = line->start_index; /* this the position where the first line wraps */
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;
1651
item->text_rect.height = 0;
1654
pango_layout_set_wrap( self->pl, 0 ); /* wrap the text */
1655
pango_layout_set_ellipsize( self->pl, PANGO_ELLIPSIZE_END );
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;
1661
item->text_rect.width = 100;
1662
item->box.height += item->text_rect.height;
1664
item->icon_rect.width = item->icon_rect.height = self->icon_size;
1667
void layout_items( DesktopWindow* self )
1671
GtkWidget* widget = (GtkWidget*)self;
1674
self->item_w = MAX( self->label_w, self->icon_size ) + self->x_pad * 2;
1676
x = self->wa.x + self->x_margin;
1677
y = self->wa.y + self->y_margin;
1679
pango_layout_set_width( self->pl, 100 * PANGO_SCALE );
1681
for( l = self->items; l; l = l->next )
1683
item = (DesktopItem*)l->data;
1688
item->box.width = self->item_w;
1689
calc_item_size( self, item );
1691
y2 = self->wa.y + self->wa.height - self->y_margin; /* bottom */
1692
if( y + item->box.height > y2 ) /* bottom is reached */
1694
y = self->wa.y + self->y_margin;
1696
y += item->box.height;
1697
x += self->item_w; /* go to the next column */
1700
else /* bottom is not reached */
1702
y += item->box.height; /* move to the next row */
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;
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;
1711
gtk_widget_queue_draw( self );
1714
void on_file_listed( VFSDir* dir, gboolean is_cancelled, DesktopWindow* self )
1716
GList* l, *items = NULL;
1720
g_mutex_lock( dir->mutex );
1721
for( l = dir->file_list; l; l = l->next )
1723
fi = (VFSFileInfo*)l->data;
1724
if( fi->name[0] == '.' ) /* skip the hidden files */
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 ); */
1731
if( vfs_file_info_is_image( fi ) )
1732
vfs_thumbnail_loader_request( dir, fi, TRUE );
1734
g_mutex_unlock( dir->mutex );
1737
self->items = g_list_sort_with_data( items, get_sort_func(self), self );
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 );
1750
item = g_slice_new0( DesktopItem );
1752
/* item->icon = vfs_file_info_get_big_thumbnail( fi ); */
1754
self->items = g_list_prepend( self->items, item );
1756
layout_items( self );
1759
void on_thumbnail_loaded( VFSDir* dir, VFSFileInfo* fi, DesktopWindow* self )
1762
GtkWidget* w = (GtkWidget*)self;
1764
for( l = self->items; l; l = l->next )
1766
DesktopItem* item = (DesktopItem*) l->data;
1767
if( item->fi == fi )
1771
g_object_unref( item->icon );
1772
item->icon = vfs_file_info_get_big_thumbnail( fi );
1774
redraw_item( self, item );
1780
void on_file_created( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
1783
DesktopWindow* self = (DesktopWindow*)user_data;
1786
/* don't show hidden files */
1787
if( file->name[0] == '.' )
1790
/* prevent duplicated items */
1791
for( l = self->items; l; l = l->next )
1793
item = (DesktopItem*)l->data;
1794
if( strcmp( file->name, item->fi->name ) == 0 )
1798
item = g_slice_new0( DesktopItem );
1799
item->fi = vfs_file_info_ref( file );
1800
/* item->icon = vfs_file_info_get_big_icon( file ); */
1802
self->items = g_list_insert_sorted_with_data( self->items, item,
1803
get_sort_func(self), self );
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 );
1810
void on_file_deleted( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
1813
DesktopWindow* self = (DesktopWindow*)user_data;
1816
/* FIXME: special handling is needed here */
1820
/* don't deal with hidden files */
1821
if( file->name[0] == '.' )
1825
for( l = self->items; l; l = l->next )
1827
item = (DesktopItem*)l->data;
1828
if( item->fi == file )
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 );
1843
void on_file_changed( VFSDir* dir, VFSFileInfo* file, gpointer user_data )
1846
DesktopWindow* self = (DesktopWindow*)user_data;
1848
GtkWidget* w = (GtkWidget*)self;
1850
/* don't touch hidden files */
1851
if( file->name[0] == '.' )
1855
for( l = self->items; l; l = l->next )
1857
item = (DesktopItem*)l->data;
1858
if( item->fi == file )
1864
item = (DesktopItem*)l->data;
1867
g_object_unref( item->icon );
1868
item->icon = vfs_file_info_get_big_icon( file );
1870
if( GTK_WIDGET_VISIBLE( w ) )
1872
/* redraw the item */
1873
redraw_item( self, item );
1879
/*-------------- Private methods -------------------*/
1881
void paint_item( DesktopWindow* self, DesktopItem* item, GdkRectangle* expose_area )
1883
/* GdkPixbuf* icon = item->icon ? gdk_pixbuf_ref(item->icon) : NULL; */
1885
const char* text = item->fi->disp_name;
1886
GtkWidget* widget = (GtkWidget*)self;
1887
GdkDrawable* drawable = widget->window;
1889
GtkCellRendererState state = 0;
1890
GdkRectangle text_rect;
1893
if( item->fi->big_thumbnail )
1894
icon = gdk_pixbuf_ref( item->fi->big_thumbnail );
1896
icon = vfs_file_info_get_big_icon( item->fi );
1898
if( item->is_selected )
1899
state = GTK_CELL_RENDERER_SELECTED;
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 );
1906
g_object_unref( icon );
1908
tmp = widget->style->fg_gc[0];
1910
text_rect = item->text_rect;
1912
pango_layout_set_wrap( self->pl, 0 );
1914
if( item->is_selected )
1916
GdkRectangle intersect={0};
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 );
1925
/* Do the drop shadow stuff... This is a little bit dirty... */
1929
gdk_gc_set_foreground( self->gc, &self->shadow );
1931
if( item->len1 > 0 )
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 );
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 );
1946
if( self->focus == item && GTK_WIDGET_HAS_FOCUS(widget) )
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);
1955
text_rect = item->text_rect;
1957
gdk_gc_set_foreground( self->gc, &self->fg );
1959
if( item->len1 > 0 )
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 );
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 );
1970
widget->style->fg_gc[0] = tmp;
1973
void move_item( DesktopWindow* self, DesktopItem* item, int x, int y, gboolean is_offset )
1975
GdkRectangle old = item->box;
1984
item->icon_rect.x += x;
1985
item->icon_rect.y += y;
1986
item->text_rect.x += x;
1987
item->text_rect.y += y;
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 );
1993
static gboolean is_point_in_rect( GdkRectangle* rect, int x, int y )
1995
return rect->x < x && x < (rect->x + rect->width) && y > rect->y && y < (rect->y + rect->height);
1998
DesktopItem* hit_test( DesktopWindow* self, int x, int y )
2002
for( l = self->items; l; l = l->next )
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 ) )
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 )
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 ),
2020
app_settings.height );
2021
gtk_widget_show( main_window );
2024
VFSFileInfo* fi = (VFSFileInfo*)folders->data;
2026
if( fi->flags & VFS_FILE_INFO_VIRTUAL )
2028
/* if this is a special item, not a real file in desktop dir */
2029
if( fi->name[0] == '/' ) /* it's a real path */
2031
path = g_strdup( fi->name );
2035
folders = folders->next;
2038
/* FIXME/TODO: In the future we should handle mounting here. */
2042
path = g_build_filename( vfs_get_desktop_dir(), fi->name, NULL );
2044
fm_main_window_add_new_tab( FM_MAIN_WINDOW( main_window ), path,
2045
app_settings.show_side_pane, app_settings.side_pane_mode );
2048
folders = folders->next;
2052
GCompareDataFunc get_sort_func( DesktopWindow* win )
2054
GCompareDataFunc comp;
2056
switch( win->sort_by )
2058
case DW_SORT_BY_NAME:
2059
comp = comp_item_by_name;
2061
case DW_SORT_BY_SIZE:
2062
comp = comp_item_by_size;
2064
case DW_SORT_BY_TYPE:
2065
comp = comp_item_by_type;
2067
case DW_SORT_BY_MTIME:
2068
comp = comp_item_by_mtime;
2070
case DW_SORT_CUSTOM:
2071
comp = comp_item_custom;
2074
comp = comp_item_by_name;
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) ) )
2084
int comp_item_by_name( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
2087
if( ret = COMP_VIRTUAL( item1, item2 ) )
2089
ret =g_utf8_collate( item1->fi->disp_name, item2->fi->disp_name );
2090
if( win->sort_type == GTK_SORT_DESCENDING )
2095
int comp_item_by_size( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
2098
if( ret = COMP_VIRTUAL( item1, item2 ) )
2100
ret =item1->fi->size - item2->fi->size;
2101
if( win->sort_type == GTK_SORT_DESCENDING )
2106
int comp_item_by_mtime( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
2109
if( ret = COMP_VIRTUAL( item1, item2 ) )
2111
ret =item1->fi->mtime - item2->fi->mtime;
2112
if( win->sort_type == GTK_SORT_DESCENDING )
2117
int comp_item_by_type( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
2120
if( ret = COMP_VIRTUAL( item1, item2 ) )
2122
ret = strcmp( item1->fi->mime_type->type, item2->fi->mime_type->type );
2124
if( win->sort_type == GTK_SORT_DESCENDING )
2129
int comp_item_custom( DesktopItem* item1, DesktopItem* item2, DesktopWindow* win )
2131
return (item1->order - item2->order);
2134
void redraw_item( DesktopWindow* win, DesktopItem* item )
2136
GdkRectangle rect = item->box;
2141
gdk_window_invalidate_rect( ((GtkWidget*)win)->window, &rect, FALSE );
2145
/* ----------------- public APIs ------------------*/
2147
void desktop_window_sort_items( DesktopWindow* win, DWSortType sort_by, GtkSortType sort_type )
2150
GList* special_items;
2152
if( win->sort_type == sort_type && win->sort_by == sort_by )
2155
app_settings.desktop_sort_by = win->sort_by = sort_by;
2156
app_settings.desktop_sort_type = win->sort_type = sort_type;
2158
/* skip the special items since they always appears first */
2159
special_items = win->items;
2160
for( items = special_items; items; items = items->next )
2162
DesktopItem* item = (DesktopItem*)items->data;
2163
if( ! (item->fi->flags & VFS_FILE_INFO_VIRTUAL) )
2170
/* the previous item of the first non-special item is the last special item */
2173
items->prev->next = NULL;
2177
items = g_list_sort_with_data( items, get_sort_func(win), win );
2178
win->items = g_list_concat( special_items, items );
2180
layout_items( win );
2183
GList* desktop_window_get_selected_items( DesktopWindow* win )
2188
for( l = win->items; l; l = l->next )
2190
DesktopItem* item = (DesktopItem*) l->data;
2191
if( item->is_selected )
2193
if( G_UNLIKELY( item == win->focus ) )
2194
sel = g_list_prepend( sel, item );
2196
sel = g_list_append( sel, item );
2203
GList* desktop_window_get_selected_files( DesktopWindow* win )
2205
GList* sel = desktop_window_get_selected_items( win );
2211
DesktopItem* item = (DesktopItem*) l->data;
2212
if( item->fi->flags & VFS_FILE_INFO_VIRTUAL )
2214
/* don't include virtual items */
2217
sel = g_list_remove_link( sel, tmp );
2218
g_list_free1( tmp );
2222
l->data = vfs_file_info_ref( item->fi );
2230
/*----------------- X11-related sutff ----------------*/
2233
GdkFilterReturn on_rootwin_event ( GdkXEvent *xevent,
2237
XPropertyEvent * evt = ( XPropertyEvent* ) xevent;
2238
DesktopWindow* self = (DesktopWindow*)data;
2240
if ( evt->type == PropertyNotify )
2242
if( evt->atom == ATOM_NET_WORKAREA )
2244
/* working area is resized */
2245
get_working_area( gtk_widget_get_screen((GtkWidget*)self), &self->wa );
2246
layout_items( self );
2249
else if( evt->atom == ATOM_XROOTMAP_ID )
2251
/* wallpaper was changed by other programs */
2255
return GDK_FILTER_TRANSLATE;
2258
/* This function is taken from xfdesktop */
2259
void forward_event_to_rootwin( GdkScreen *gscreen, GdkEvent *event )
2261
XButtonEvent xev, xev2;
2262
Display *dpy = GDK_DISPLAY_XDISPLAY( gdk_screen_get_display( gscreen ) );
2264
if ( event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE )
2266
if ( event->type == GDK_BUTTON_PRESS )
2268
xev.type = ButtonPress;
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?
2274
XUngrabPointer( dpy, event->button.time );
2277
xev.type = ButtonRelease;
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;
2288
else if ( event->type == GDK_SCROLL )
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;
2298
xev2.type = ButtonRelease;
2299
xev2.button = xev.button;
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;
2309
XSendEvent( dpy, xev.window, False, ButtonPressMask | ButtonReleaseMask,
2310
( XEvent * ) & xev );
2311
if ( xev2.type == 0 )
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;
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;
2326
XSendEvent( dpy, xev2.window, False, ButtonPressMask | ButtonReleaseMask,
2327
( XEvent * ) & xev2 );
2331
GdkPixmap* get_root_pixmap( GdkWindow* root )
2333
Pixmap root_pix = None;
2338
Pixmap *data = NULL;
2342
result = XGetWindowProperty(
2343
GDK_WINDOW_XDISPLAY( root ),
2344
GDK_WINDOW_XID( root ),
2348
&type, &format, &n_items,
2349
&bytes_after, (unsigned char **)&data);
2351
if (result == Success && n_items)
2357
return root_pix ? gdk_pixmap_foreign_new( root_pix ) : NULL;
2360
gboolean set_root_pixmap( GdkWindow* root, GdkPixmap* pix )