4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
8 /* filer.c - code for handling filer windows */
17 #include <gdk/gdkprivate.h> /* XXX - find another way to do this */
18 #include <collection.h>
21 #include "gui_support.h"
27 static int number_of_windows
= 0;
28 static FilerWindow
*window_with_selection
= NULL
;
30 /* Static prototypes */
31 static void filer_window_destroyed(GtkWidget
*widget
,
32 FilerWindow
*filer_window
);
33 static gboolean
idle_scan_dir(gpointer data
);
34 static void draw_item(GtkWidget
*widget
,
37 void show_menu(Collection
*collection
, GdkEventButton
*event
,
38 int number_selected
, gpointer user_data
);
39 static int sort_by_name(const void *item1
, const void *item2
);
40 static void scan_dir(FilerWindow
*filer_window
);
41 static void add_item(FilerWindow
*filer_window
, char *leafname
);
42 static gboolean
test_point(Collection
*collection
,
43 int point_x
, int point_y
,
45 int width
, int height
);
48 static void filer_window_destroyed(GtkWidget
*widget
,
49 FilerWindow
*filer_window
)
51 if (window_with_selection
== filer_window
)
52 window_with_selection
= NULL
;
54 if (filer_window
->dir
)
56 closedir(filer_window
->dir
);
57 gtk_idle_remove(filer_window
->idle_scan_id
);
59 g_free(filer_window
->path
);
62 if (--number_of_windows
< 1)
66 /* This is called while we are scanning the directory */
67 static gboolean
idle_scan_dir(gpointer data
)
70 FilerWindow
*filer_window
= (FilerWindow
*) data
;
74 next
= readdir(filer_window
->dir
);
77 closedir(filer_window
->dir
);
78 filer_window
->dir
= NULL
;
80 collection_qsort(filer_window
->collection
,
82 return FALSE
; /* Finished */
85 add_item(filer_window
, next
->d_name
);
86 } while (!gtk_events_pending());
91 /* Add a single object to a directory display */
92 static void add_item(FilerWindow
*filer_window
, char *leafname
)
100 /* Ignore dot files (should be an option) */
101 if (leafname
[0] == '.')
104 item
= g_malloc(sizeof(FileItem
));
105 item
->leafname
= g_strdup(leafname
);
108 path
= make_path(filer_window
->path
, leafname
);
109 if (lstat(path
->str
, &info
))
110 base_type
= TYPE_ERROR
;
113 if (S_ISREG(info
.st_mode
))
114 base_type
= TYPE_FILE
;
115 else if (S_ISDIR(info
.st_mode
))
116 base_type
= TYPE_DIRECTORY
;
117 else if (S_ISBLK(info
.st_mode
))
118 base_type
= TYPE_BLOCK_DEVICE
;
119 else if (S_ISCHR(info
.st_mode
))
120 base_type
= TYPE_CHAR_DEVICE
;
121 else if (S_ISFIFO(info
.st_mode
))
122 base_type
= TYPE_PIPE
;
123 else if (S_ISSOCK(info
.st_mode
))
124 base_type
= TYPE_SOCKET
;
125 else if (S_ISLNK(info
.st_mode
))
127 if (stat(path
->str
, &info
))
129 base_type
= TYPE_ERROR
;
133 if (S_ISREG(info
.st_mode
))
134 base_type
= TYPE_FILE
;
135 else if (S_ISDIR(info
.st_mode
))
136 base_type
= TYPE_DIRECTORY
;
137 else if (S_ISBLK(info
.st_mode
))
138 base_type
= TYPE_BLOCK_DEVICE
;
139 else if (S_ISCHR(info
.st_mode
))
140 base_type
= TYPE_CHAR_DEVICE
;
141 else if (S_ISFIFO(info
.st_mode
))
142 base_type
= TYPE_PIPE
;
143 else if (S_ISSOCK(info
.st_mode
))
144 base_type
= TYPE_SOCKET
;
146 base_type
= TYPE_UNKNOWN
;
149 item
->flags
|= ITEM_FLAG_SYMLINK
;
152 base_type
= TYPE_UNKNOWN
;
155 if (base_type
== TYPE_DIRECTORY
)
157 /* Might be an application directory - better check... */
158 path
= g_string_append(path
, "/AppInfo");
159 if (!stat(path
->str
, &info
))
161 base_type
= TYPE_APPDIR
;
164 item
->base_type
= base_type
;
166 item
->text_width
= gdk_string_width(filer_window
->window
->style
->font
,
168 item
->image
= default_pixmap
+ base_type
;
170 /* XXX: Must be a better way... */
171 item
->pix_width
= ((GdkPixmapPrivate
*) item
->image
->pixmap
)->width
;
173 item_width
= MAX(item
->pix_width
, item
->text_width
) + 4;
175 if (item_width
> filer_window
->collection
->item_width
)
176 collection_set_item_size(filer_window
->collection
,
178 filer_window
->collection
->item_height
);
180 collection_insert(filer_window
->collection
, item
);
183 static gboolean
test_point(Collection
*collection
,
184 int point_x
, int point_y
,
185 CollectionItem
*item
,
186 int width
, int height
)
188 FileItem
*fileitem
= (FileItem
*) item
->data
;
189 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
190 int text_height
= font
->ascent
+ font
->descent
;
191 int x_off
= ABS(point_x
- (width
>> 1));
193 if (x_off
<= (fileitem
->pix_width
>> 1) + 2 &&
194 point_y
< height
- text_height
- 2 &&
198 if (x_off
<= (fileitem
->text_width
>> 1) + 2 &&
199 point_y
> height
- text_height
- 2)
205 static void draw_item(GtkWidget
*widget
,
206 CollectionItem
*colitem
,
209 FileItem
*item
= (FileItem
*) colitem
->data
;
210 GdkGC
*gc
= colitem
->selected
? widget
->style
->white_gc
211 : widget
->style
->black_gc
;
212 int image_x
= area
->x
+ ((area
->width
- item
->pix_width
) >> 1);
213 GdkFont
*font
= widget
->style
->font
;
214 int text_x
= area
->x
+ ((area
->width
- item
->text_width
) >> 1);
215 int text_y
= area
->y
+ area
->height
- font
->descent
- 2;
216 int text_height
= font
->ascent
+ font
->descent
;
220 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
221 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
222 gdk_draw_pixmap(widget
->window
, gc
,
224 0, 0, /* Source x,y */
225 image_x
, area
->y
+ 8, /* Dest x,y */
228 if (item
->flags
& ITEM_FLAG_SYMLINK
)
230 gdk_gc_set_clip_mask(gc
,
231 default_pixmap
[TYPE_SYMLINK
].mask
);
232 gdk_draw_pixmap(widget
->window
, gc
,
233 default_pixmap
[TYPE_SYMLINK
].pixmap
,
234 0, 0, /* Source x,y */
235 image_x
, area
->y
+ 8, /* Dest x,y */
239 gdk_gc_set_clip_mask(gc
, NULL
);
240 gdk_gc_set_clip_origin(gc
, 0, 0);
243 if (colitem
->selected
)
244 gtk_paint_flat_box(widget
->style
, widget
->window
,
245 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
246 NULL
, widget
, "text",
247 text_x
, text_y
- font
->ascent
,
251 gdk_draw_text(widget
->window
,
253 colitem
->selected
? widget
->style
->white_gc
254 : widget
->style
->black_gc
,
256 item
->leafname
, strlen(item
->leafname
));
259 void show_menu(Collection
*collection
, GdkEventButton
*event
,
260 int number_selected
, gpointer user_data
)
262 show_filer_menu((FilerWindow
*) user_data
, event
);
265 static void scan_dir(FilerWindow
*filer_window
)
267 g_return_if_fail(filer_window
->dir
== NULL
); /* XXX */
269 filer_window
->dir
= opendir(filer_window
->path
);
270 if (!filer_window
->dir
)
272 report_error("Error scanning directory:", g_strerror(errno
));
276 filer_window
->idle_scan_id
= gtk_idle_add(idle_scan_dir
, filer_window
);
279 static void gain_selection(Collection
*collection
,
280 gint number_selected
,
283 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
285 if (window_with_selection
&& window_with_selection
!= filer_window
)
286 collection_clear_selection(window_with_selection
->collection
);
288 window_with_selection
= filer_window
;
291 static int sort_by_name(const void *item1
, const void *item2
)
293 return strcmp((*((FileItem
**)item1
))->leafname
,
294 (*((FileItem
**)item2
))->leafname
);
297 void open_item(Collection
*collection
,
298 gpointer item_data
, int item_number
,
301 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
302 FileItem
*item
= (FileItem
*) item_data
;
304 if (item
->base_type
== TYPE_DIRECTORY
)
305 filer_opendir(make_path(filer_window
->path
,
306 item
->leafname
)->str
);
309 void filer_opendir(char *path
)
311 GtkWidget
*hbox
, *scrollbar
, *collection
;
312 FilerWindow
*filer_window
;
314 filer_window
= g_malloc(sizeof(FilerWindow
));
315 filer_window
->path
= pathdup(path
);
316 filer_window
->dir
= NULL
; /* Not scanning */
318 collection
= collection_new(NULL
);
319 filer_window
->collection
= COLLECTION(collection
);
320 collection_set_functions(filer_window
->collection
,
321 draw_item
, test_point
);
323 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
324 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
326 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
329 hbox
= gtk_hbox_new(FALSE
, 0);
330 gtk_container_add(GTK_CONTAINER(filer_window
->window
), hbox
);
332 gtk_box_pack_start(GTK_BOX(hbox
), collection
, TRUE
, TRUE
, 0);
334 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
335 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
337 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
338 open_item
, filer_window
);
339 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
340 filer_window_destroyed
, filer_window
);
341 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
342 show_menu
, filer_window
);
343 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
344 gain_selection
, filer_window
);
345 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
346 drag_selection
, filer_window
);
347 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
348 drag_data_get
, filer_window
);
350 gtk_widget_show_all(filer_window
->window
);
353 load_default_pixmaps(collection
->window
);
355 scan_dir(filer_window
);