1 /*
2  * Copyright (C) 2005 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  */
19 
20 #define LOCAL_DEBUG
21 #include "../configure.h"
22 
23 #include "../libAfterStep/asapp.h"
24 #include "../libAfterStep/screen.h"
25 #include "../libAfterImage/afterimage.h"
26 
27 
28 #include "asgtk.h"
29 #include "asgtkai.h"
30 #include "asgtkimagedir.h"
31 #include "asgtkimageview.h"
32 #include "asgtkimagebrowser.h"
33 
34 #define DIR_LIST_WIDTH   200
35 #define DIR_LIST_HEIGHT  150
36 #define FILE_LIST_WIDTH  200
37 #define FILE_LIST_HEIGHT 210
38 #define PREVIEW_WIDTH  480
39 #define PREVIEW_HEIGHT 360
40 
41 
42 /*  local function prototypes  */
43 static void asgtk_image_browser_class_init (ASGtkImageBrowserClass *
44 																						klass);
45 static void asgtk_image_browser_init (ASGtkImageBrowser * ib);
46 static void asgtk_image_browser_dispose (GObject * object);
47 static void asgtk_image_browser_finalize (GObject * object);
48 static void asgtk_image_browser_style_set (GtkWidget * widget,
49 																					 GtkStyle * prev_style);
50 
51 /*  private variables  */
52 static GtkWindowClass *parent_class = NULL;
53 
asgtk_image_browser_get_type(void)54 GType asgtk_image_browser_get_type (void)
55 {
56 	static GType ib_type = 0;
57 
58 	if (!ib_type) {
59 		static const GTypeInfo ib_info = {
60 			sizeof (ASGtkImageBrowserClass),
61 			(GBaseInitFunc) NULL,
62 			(GBaseFinalizeFunc) NULL,
63 			(GClassInitFunc) asgtk_image_browser_class_init,
64 			NULL,											/* class_finalize */
65 			NULL,											/* class_data     */
66 			sizeof (ASGtkImageBrowser),
67 			0,												/* n_preallocs    */
68 			(GInstanceInitFunc) asgtk_image_browser_init,
69 		};
70 
71 		ib_type =
72 				g_type_register_static (GTK_TYPE_WINDOW, "ASGtkImageBrowser",
73 																&ib_info, 0);
74 	}
75 
76 	return ib_type;
77 }
78 
asgtk_image_browser_class_init(ASGtkImageBrowserClass * klass)79 static void asgtk_image_browser_class_init (ASGtkImageBrowserClass * klass)
80 {
81 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
82 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
83 
84 	parent_class = g_type_class_peek_parent (klass);
85 
86 	object_class->dispose = asgtk_image_browser_dispose;
87 	object_class->finalize = asgtk_image_browser_finalize;
88 
89 	widget_class->style_set = asgtk_image_browser_style_set;
90 
91 }
92 
asgtk_image_browser_init(ASGtkImageBrowser * ib)93 static void asgtk_image_browser_init (ASGtkImageBrowser * ib)
94 {
95 }
96 
asgtk_image_browser_dispose(GObject * object)97 static void asgtk_image_browser_dispose (GObject * object)
98 {
99 	/* ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (object); */
100 	G_OBJECT_CLASS (parent_class)->dispose (object);
101 }
102 
asgtk_image_browser_finalize(GObject * object)103 static void asgtk_image_browser_finalize (GObject * object)
104 {
105 	G_OBJECT_CLASS (parent_class)->finalize (object);
106 }
107 
108 static void
asgtk_image_browser_style_set(GtkWidget * widget,GtkStyle * prev_style)109 asgtk_image_browser_style_set (GtkWidget * widget, GtkStyle * prev_style)
110 {
111 	/* ASGtkImageBrowser *id = ASGTK_IMAGE_BROWSER (widget); */
112 
113 	GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
114 }
115 
asgtk_image_browser_make_fullfilename(ASGtkImageBrowser * ib,const char * filename)116 static char *asgtk_image_browser_make_fullfilename (ASGtkImageBrowser * ib,
117 																										const char *filename)
118 {
119 	if (filename[0] == '.' && filename[1] == '\0')
120 		return mystrdup (ib->current_dir);
121 
122 	if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
123 		char *sep = strrchr (ib->current_dir, '/');
124 
125 		if (sep > ib->current_dir)
126 			return mystrndup (ib->current_dir, sep - ib->current_dir);
127 
128 		return mystrdup ("/");
129 	}
130 
131 	if (filename[0] == '/')
132 		return mystrdup (filename);
133 
134 	return make_file_name (ib->current_dir, filename);
135 }
136 
137 static void
asgtk_image_browser_dir_activate(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)138 asgtk_image_browser_dir_activate (GtkTreeView * tree_view,
139 																	GtkTreePath * path,
140 																	GtkTreeViewColumn * column,
141 																	gpointer user_data)
142 {
143 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
144 	GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
145 	GtkTreeIter iter;
146 	char *filename;
147 
148 	gtk_tree_model_get_iter (model, &iter, path);
149 	gtk_tree_model_get (model, &iter, 0, &filename, -1);
150 	LOCAL_DEBUG_OUT ("filename == \"%s\"", filename);
151 	/* TODO : change directory/populate file list */
152 	if (filename[0] == '.' && filename[1] == '\0') {
153 		/* already in current dir - do nothing */
154 	} else {
155 		filename = asgtk_image_browser_make_fullfilename (ib, filename);
156 		asgtk_image_browser_change_dir (ib, filename);
157 		free (filename);
158 	}
159 }
160 
161 static void
asgtk_image_browser_dir_select(GtkTreeSelection * selection,gpointer user_data)162 asgtk_image_browser_dir_select (GtkTreeSelection * selection,
163 																gpointer user_data)
164 {
165 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
166 	char *filename;
167 	GtkTreeIter iter;
168 	GtkTreeModel *model;
169 
170 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
171 		gtk_tree_model_get (model, &iter, 0, &filename, -1);
172 		LOCAL_DEBUG_OUT ("filename == \"%s\"", filename);
173 		/* TODO : change directory/populate file list */
174 		if (filename[0] == '.' && filename[1] == '\0')
175 			asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir),
176 																ib->current_dir);
177 		else {
178 			filename = asgtk_image_browser_make_fullfilename (ib, filename);
179 			asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir), filename);
180 			free (filename);
181 		}
182 	}
183 }
184 
on_root_clicked(GtkButton * button,gpointer user_data)185 static void on_root_clicked (GtkButton * button, gpointer user_data)
186 {
187 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
188 
189 	asgtk_image_browser_change_dir (ib, "/");
190 }
191 
on_home_clicked(GtkButton * button,gpointer user_data)192 static void on_home_clicked (GtkButton * button, gpointer user_data)
193 {
194 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
195 
196 	asgtk_image_browser_change_dir (ib, "~/");
197 }
198 
199 
200 static void
asgtk_image_browser_path_entry(GtkWidget * widget,gpointer data)201 asgtk_image_browser_path_entry (GtkWidget * widget, gpointer data)
202 {
203 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);
204 
205 	if (ib->path_entry) {
206 		const gchar *entry_text =
207 				gtk_entry_get_text (GTK_ENTRY (ib->path_entry));
208 
209 		asgtk_image_browser_change_dir (ib, entry_text);
210 	}
211 }
212 
213 static void
asgtk_image_browser_path_changed(GtkWidget * widget,gpointer data)214 asgtk_image_browser_path_changed (GtkWidget * widget, gpointer data)
215 {
216 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);
217 
218 	if (ib) {
219 		const gchar *entry_text =
220 				asgtk_combo_box_get_active_text (GTK_COMBO_BOX (ib->path_combo));
221 
222 		asgtk_image_browser_change_dir (ib, entry_text);
223 	}
224 }
225 
226 static void
asgtk_image_browser_scale_toggle(GtkWidget * checkbutton,gpointer data)227 asgtk_image_browser_scale_toggle (GtkWidget * checkbutton, gpointer data)
228 {
229 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);
230 
231 	asgtk_image_view_set_resize (ib->preview,
232 															 GTK_TOGGLE_BUTTON (checkbutton)->active ?
233 															 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW : 0,
234 															 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW);
235 }
236 
237 
238 
239 static void
asgtk_image_browser_create_dir_list(ASGtkImageBrowser * ib,GtkWidget * list_vbox)240 asgtk_image_browser_create_dir_list (ASGtkImageBrowser * ib,
241 																		 GtkWidget * list_vbox)
242 {
243 	GtkWidget *scrolled_win, *model;
244 	GtkTreeViewColumn *column;
245 
246 	model = GTK_WIDGET (gtk_list_store_new (1, G_TYPE_STRING));
247 	ib->dir_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
248 	g_object_unref (model);
249 
250 	column =
251 			gtk_tree_view_column_new_with_attributes ("Folders",
252 																								gtk_cell_renderer_text_new
253 																								(), "text", 0, NULL);
254 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
255 	gtk_tree_view_append_column (GTK_TREE_VIEW (ib->dir_list), column);
256 
257 	gtk_widget_set_size_request (ib->dir_list, DIR_LIST_WIDTH,
258 															 DIR_LIST_HEIGHT);
259 	g_signal_connect (ib->dir_list, "row_activated",
260 										G_CALLBACK (asgtk_image_browser_dir_activate), ib);
261 	g_signal_connect (gtk_tree_view_get_selection
262 										(GTK_TREE_VIEW (ib->dir_list)), "changed",
263 										G_CALLBACK (asgtk_image_browser_dir_select), ib);
264 
265 	scrolled_win =
266 			ASGTK_SCROLLED_WINDOW (GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS,
267 														 GTK_SHADOW_IN);
268 
269 	ASGTK_CONTAINER_CONFIG (scrolled_win, DIR_LIST_WIDTH, DIR_LIST_HEIGHT,
270 													0);
271 	ASGTK_CONTAINER_ADD (scrolled_win, ib->dir_list);
272 	if (GTK_IS_PANED (list_vbox))
273 		gtk_paned_pack1 (GTK_PANED (list_vbox), GTK_WIDGET (scrolled_win),
274 										 TRUE, TRUE);
275 	else
276 		gtk_box_pack_end (GTK_BOX (list_vbox), GTK_WIDGET (scrolled_win), TRUE,
277 											TRUE, 0);
278 
279 	gtk_widget_show (scrolled_win);
280 	colorize_gtk_tree_view_window (GTK_WIDGET (scrolled_win));
281 }
282 
283 static void
asgtk_image_browser_file_sel_handler(ASGtkImageDir * id,gpointer user_data)284 asgtk_image_browser_file_sel_handler (ASGtkImageDir * id,
285 																			gpointer user_data)
286 {
287 	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
288 
289 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
290 	if (ib) {
291 		ASImageListEntry *le = asgtk_image_dir_get_selection (id);
292 
293 		asgtk_image_view_set_entry (ib->preview, le);
294 		if (le)
295 			unref_asimage_list_entry (le);
296 	}
297 }
298 
299 
300 /*  public functions  */
asgtk_image_browser_new()301 GtkWidget *asgtk_image_browser_new ()
302 {
303 	ASGtkImageBrowser *ib;
304 	GtkWidget *main_vbox;
305 	GtkWidget *shortcuts_hbox, *btn;
306 	GtkWidget *list_vbox, *preview_vbox;
307 
308 	ib = g_object_new (ASGTK_TYPE_IMAGE_BROWSER, NULL);
309 	colorize_gtk_window (GTK_WIDGET (ib));
310 
311 	gtk_container_set_border_width (GTK_CONTAINER (ib), 5);
312 	main_vbox = gtk_vbox_new (FALSE, 0);
313 	gtk_widget_show (main_vbox);
314 	gtk_container_add (GTK_CONTAINER (ib), main_vbox);
315 	gtk_box_set_spacing (GTK_BOX (main_vbox), 5);
316 
317 	shortcuts_hbox = gtk_hbox_new (FALSE, 0);
318 	gtk_widget_show (shortcuts_hbox);
319 	gtk_box_pack_start (GTK_BOX (main_vbox), shortcuts_hbox, FALSE, FALSE,
320 											0);
321 	gtk_box_set_spacing (GTK_BOX (shortcuts_hbox), 5);
322 
323 	btn =
324 			asgtk_add_button_to_box (GTK_BOX (shortcuts_hbox),
325 															 GTK_STOCK_GOTO_TOP, "/",
326 															 G_CALLBACK (on_root_clicked), ib);
327 	gtk_widget_set_size_request (btn, 50, -1);
328 	btn =
329 			asgtk_add_button_to_box (GTK_BOX (shortcuts_hbox), GTK_STOCK_HOME,
330 															 "~/", G_CALLBACK (on_home_clicked), ib);
331 	gtk_widget_set_size_request (btn, 50, -1);
332 
333 	ib->path_combo = gtk_combo_box_entry_new_text ();
334 	//gtk_widget_set_size_request ( ib->path_combo, DIR_LIST_WIDTH+300-105 , -1);
335 	gtk_box_pack_end (GTK_BOX (shortcuts_hbox), ib->path_combo, TRUE, TRUE,
336 										10);
337 	gtk_widget_show (ib->path_combo);
338 	colorize_gtk_edit (ib->path_combo);
339 	ib->path_entry = NULL;
340 	/* path_entry is actually found trough the following discovery process :  */
341 	if (GTK_IS_CONTAINER (ib->path_combo))
342 		gtk_container_forall (GTK_CONTAINER (ib->path_combo),
343 													find_combobox_entry, &(ib->path_entry));
344 	/* if above succeeded then path_entry should be not NULL here : */
345 	if (ib->path_entry)
346 		g_signal_connect (G_OBJECT (ib->path_entry), "activate",
347 											G_CALLBACK (asgtk_image_browser_path_entry),
348 											(gpointer) ib);
349 	g_signal_connect (G_OBJECT (ib->path_combo), "changed",
350 										G_CALLBACK (asgtk_image_browser_path_changed),
351 										(gpointer) ib);
352 
353 
354 #if 0
355 	ib->list_hbox = gtk_hbox_new (FALSE, 0);
356 #else
357 	ib->list_hbox = gtk_hpaned_new ();
358 	colorize_gtk_widget (ib->list_hbox, get_colorschemed_style_normal ());
359 #endif
360 	gtk_widget_show (ib->list_hbox);
361 	gtk_box_pack_start (GTK_BOX (main_vbox), ib->list_hbox, TRUE, TRUE, 0);
362 
363 	ib->main_buttons_hbox = gtk_hbutton_box_new ();
364 	gtk_hbutton_box_set_layout_default (GTK_BUTTONBOX_SPREAD);
365 	gtk_widget_show (ib->main_buttons_hbox);
366 	gtk_box_pack_end (GTK_BOX (main_vbox), ib->main_buttons_hbox, FALSE,
367 										FALSE, 5);
368 
369 
370 	/* separator really goes above the buttons box, so it is added second from the end ! */
371 	ib->separator = gtk_hseparator_new ();
372 	gtk_box_pack_end (GTK_BOX (main_vbox), ib->separator, FALSE, FALSE, 5);
373 	colorize_gtk_widget (GTK_WIDGET (ib->separator),
374 											 get_colorschemed_style_button ());
375 
376 	/* now designing dirlist controls : */
377 #if 0
378 	list_vbox = gtk_vbox_new (FALSE, 0);
379 #else
380 	list_vbox = gtk_vpaned_new ();
381 	colorize_gtk_widget (list_vbox, get_colorschemed_style_normal ());
382 #endif
383 	gtk_widget_show (list_vbox);
384 
385 	if (GTK_IS_PANED (ib->list_hbox))
386 		gtk_paned_pack1 (GTK_PANED (ib->list_hbox), list_vbox, FALSE, FALSE);
387 	else
388 		gtk_box_pack_start (GTK_BOX (ib->list_hbox), list_vbox, FALSE, FALSE,
389 												0);
390 
391 	/* dir list : */
392 	asgtk_image_browser_create_dir_list (ib, list_vbox);
393 	/* image file list : */
394 	ib->image_dir = ASGTK_IMAGE_DIR (asgtk_image_dir_new ());
395 	if (GTK_IS_PANED (list_vbox))
396 		gtk_paned_pack2 (GTK_PANED (list_vbox), GTK_WIDGET (ib->image_dir),
397 										 TRUE, TRUE);
398 	else
399 		gtk_box_pack_end (GTK_BOX (list_vbox), GTK_WIDGET (ib->image_dir),
400 											TRUE, TRUE, 0);
401 
402 	gtk_widget_set_size_request (GTK_WIDGET (ib->image_dir), FILE_LIST_WIDTH,
403 															 FILE_LIST_HEIGHT);
404 	gtk_widget_show (GTK_WIDGET (ib->image_dir));
405 
406 	asgtk_image_dir_set_title (ASGTK_IMAGE_DIR (ib->image_dir),
407 														 "Image files:");
408 
409 	/* now designing preview controls : */
410 	preview_vbox = gtk_vbox_new (FALSE, 0);
411 	gtk_widget_show (preview_vbox);
412 	if (GTK_IS_PANED (ib->list_hbox))
413 		gtk_paned_pack2 (GTK_PANED (ib->list_hbox), preview_vbox, TRUE, TRUE);
414 	else
415 		gtk_box_pack_end (GTK_BOX (ib->list_hbox), preview_vbox, TRUE, TRUE,
416 											5);
417 
418 	ib->preview = ASGTK_IMAGE_VIEW (asgtk_image_view_new ());
419 	gtk_widget_set_size_request (GTK_WIDGET (ib->preview), PREVIEW_WIDTH,
420 															 PREVIEW_HEIGHT);
421 	gtk_box_pack_start (GTK_BOX (preview_vbox), GTK_WIDGET (ib->preview),
422 											TRUE, TRUE, 0);
423 	gtk_widget_show (GTK_WIDGET (ib->preview));
424 	asgtk_image_view_set_resize (ib->preview, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW,
425 															 ASGTK_IMAGE_VIEW_RESIZE_ALL);
426 
427 	ib->scale_check_box = gtk_check_button_new_with_label ("Scale to fit");
428 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ib->scale_check_box),
429 																TRUE);
430 	gtk_widget_show (ib->scale_check_box);
431 	colorize_gtk_widget (ib->scale_check_box,
432 											 get_colorschemed_style_normal ());
433 	g_signal_connect (G_OBJECT (ib->scale_check_box), "toggled",
434 										G_CALLBACK (asgtk_image_browser_scale_toggle),
435 										(gpointer) ib);
436 
437 	gtk_button_set_alignment (GTK_BUTTON (ib->scale_check_box), 1.0, 0.5);
438 	asgtk_image_view_add_detail (ib->preview, ib->scale_check_box, 0);
439 	/* changing to default dir : */
440 	asgtk_image_dir_set_sel_handler (ASGTK_IMAGE_DIR (ib->image_dir),
441 																	 asgtk_image_browser_file_sel_handler,
442 																	 ib);
443 	asgtk_image_browser_change_dir (ib, NULL);
444 
445 	LOCAL_DEBUG_OUT ("created image ASGtkImageBrowser object %p", ib);
446 	return GTK_WIDGET (ib);
447 }
448 
asgtk_image_browser_add_main_button(ASGtkImageBrowser * ib,const char * stock,GCallback func,gpointer user_data)449 GtkWidget *asgtk_image_browser_add_main_button (ASGtkImageBrowser * ib,
450 																								const char *stock,
451 																								GCallback func,
452 																								gpointer user_data)
453 {
454 	if (!ASGTK_IS_IMAGE_BROWSER (ib))
455 		return NULL;
456 
457 	gtk_widget_show (ib->separator);
458 	return asgtk_add_button_to_box (GTK_BOX (ib->main_buttons_hbox), stock,
459 																	NULL, func, user_data);
460 }
461 
asgtk_image_browser_add_selection_button(ASGtkImageBrowser * ib,const char * stock,GCallback func)462 GtkWidget *asgtk_image_browser_add_selection_button (ASGtkImageBrowser *
463 																										 ib, const char *stock,
464 																										 GCallback func)
465 {
466 	GtkWidget *btn;
467 
468 	if (!ASGTK_IS_IMAGE_BROWSER (ib))
469 		return NULL;
470 
471 	btn = asgtk_add_button_to_box (NULL, stock, NULL, func, ib->image_dir);
472 	asgtk_image_view_add_tool (ib->preview, btn, 0);
473 	return btn;
474 }
475 
asgtk_image_browser_refresh(ASGtkImageBrowser * ib)476 void asgtk_image_browser_refresh (ASGtkImageBrowser * ib)
477 {
478 	GtkListStore *dir_store;
479 	GtkTreeIter iter;
480 
481 	g_return_if_fail (ASGTK_IS_IMAGE_BROWSER (ib));
482 	LOCAL_DEBUG_OUT (" refreshing %p: current dir = \"%s\"", ib,
483 									 ib->current_dir ? ib->current_dir : "null");
484 	asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir),
485 														ib->current_dir);
486 	dir_store =
487 			GTK_LIST_STORE (gtk_tree_view_get_model
488 											(GTK_TREE_VIEW (ib->dir_list)));
489 	gtk_list_store_clear (dir_store);
490 	if (ib->current_dir != NULL) {
491 		/* Add current dir entry as the first item : */
492 		gtk_list_store_append (dir_store, &iter);
493 		gtk_list_store_set (dir_store, &iter, 0, ".", -1);
494 
495 		if (strcmp (ib->current_dir, "/") != 0) {
496 			gtk_list_store_append (dir_store, &iter);
497 			gtk_list_store_set (dir_store, &iter, 0, "..", -1);
498 		}
499 
500 		/* Add subdirs : */
501 		{
502 			struct direntry **list = NULL;
503 			int n = my_scandir (ib->current_dir, &list, NULL, NULL);
504 
505 			LOCAL_DEBUG_OUT (" scandir indicates %d entries in list", n);
506 			if (n > 0) {
507 				int i;
508 
509 				for (i = 0; i < n; i++) {
510 					if (S_ISDIR (list[i]->d_mode)) {
511 						Bool skip = False;
512 
513 						if (list[i]->d_name[0] == '.') {
514 							skip = (list[i]->d_name[1] == '\0' ||
515 											(list[i]->d_name[1] == '.'
516 											 && list[i]->d_name[2] == '\0'));
517 						}
518 						if (!skip) {
519 							gtk_list_store_append (dir_store, &iter);
520 							gtk_list_store_set (dir_store, &iter, 0, list[i]->d_name,
521 																	-1);
522 						}
523 					}
524 					free (list[i]);
525 				}
526 				free (list);
527 			}
528 		}
529 
530 		/* Add dirs above us : */
531 		{
532 			char *above_dir = mystrdup (ib->current_dir);
533 			int i = strlen (above_dir) - 1;
534 
535 			while (--i > 0) {
536 				if (above_dir[i] == '/') {
537 					above_dir[i] = '\0';
538 					gtk_list_store_append (dir_store, &iter);
539 					gtk_list_store_set (dir_store, &iter, 0, above_dir, -1);
540 				}
541 			}
542 		}
543 	}
544 	if (ib->current_dir == NULL || strcmp (ib->current_dir, "/") != 0) {
545 		gtk_list_store_append (dir_store, &iter);
546 		gtk_list_store_set (dir_store, &iter, 0, "/", -1);
547 	}
548 	/*
549 	   :sG:
550 	   The following 3 lines make the file lists sorted by
551 	   the Directory Name, Ascending.
552 
553 	   For general directory listing (not files)
554 	 */
555 	GtkTreeSortable *sortable;
556 
557 	sortable = GTK_TREE_SORTABLE (dir_store);
558 	gtk_tree_sortable_set_sort_column_id (sortable, 0, GTK_SORT_ASCENDING);
559 
560 
561 }
562 
add_dir_to_history(ASGtkImageBrowser * ib,const char * dir)563 static void add_dir_to_history (ASGtkImageBrowser * ib, const char *dir)
564 {
565 	g_signal_handlers_block_by_func (G_OBJECT (ib->path_combo),
566 																	 G_CALLBACK
567 																	 (asgtk_image_browser_path_changed),
568 																	 (gpointer) ib);
569 
570 	asgtk_combo_box_add_to_history (GTK_COMBO_BOX (ib->path_combo), dir);
571 	g_signal_handlers_unblock_by_func (G_OBJECT (ib->path_combo),
572 																		 G_CALLBACK
573 																		 (asgtk_image_browser_path_changed),
574 																		 (gpointer) ib);
575 
576 }
577 
578 void
asgtk_image_browser_change_dir(ASGtkImageBrowser * ib,const char * dir)579 asgtk_image_browser_change_dir (ASGtkImageBrowser * ib, const char *dir)
580 {
581 	char *fullfilename;
582 	int fullnamelen;
583 
584 	g_return_if_fail (ASGTK_IS_IMAGE_BROWSER (ib));
585 
586 	if (dir == NULL)
587 		fullfilename = PutHome ("~/");
588 	else if (dir[0] == '/')
589 		fullfilename = mystrdup (dir);
590 	else
591 		fullfilename = PutHome (dir);
592 
593 	fullnamelen = strlen (fullfilename);
594 	while (fullnamelen > 1 && fullfilename[fullnamelen - 1] == '/') {
595 		fullfilename[fullnamelen - 1] = '\0';
596 		--fullnamelen;
597 	}
598 
599 	LOCAL_DEBUG_OUT
600 			(" changing dir for  %p: current dir = \"%s\", new dir = \"%s\"", ib,
601 			 ib->current_dir ? ib->current_dir : "null", fullfilename);
602 	if (ib->current_dir == NULL
603 			|| strcmp (ib->current_dir, fullfilename) != 0) {
604 		char *title = safemalloc (128 + fullnamelen + 1);
605 
606 		if (ib->current_dir)
607 			free (ib->current_dir);
608 
609 		ib->current_dir = fullfilename;
610 		sprintf (title, "AfterStep image browser: %s", fullfilename);
611 		gtk_window_set_title (GTK_WINDOW (ib), title);
612 		free (title);
613 		add_dir_to_history (ib, fullfilename);
614 		asgtk_image_browser_refresh (ib);
615 	}
616 
617 }
618