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 #include <unistd.h>
28 
29 #include "asgtk.h"
30 #include "asgtkai.h"
31 #include "asgtkimagedir.h"
32 #include "asgtkimageview.h"
33 
34 /*  local function prototypes  */
35 static void asgtk_image_dir_class_init (ASGtkImageDirClass * klass);
36 static void asgtk_image_dir_init (ASGtkImageDir * iv);
37 static void asgtk_image_dir_dispose (GObject * object);
38 static void asgtk_image_dir_finalize (GObject * object);
39 static void asgtk_image_dir_style_set (GtkWidget * widget,
40 																			 GtkStyle * prev_style);
41 
42 
43 /*  private variables  */
44 static GtkScrolledWindowClass *parent_class = NULL;
45 
asgtk_image_dir_get_type(void)46 GType asgtk_image_dir_get_type (void)
47 {
48 	static GType id_type = 0;
49 
50 	if (!id_type) {
51 		static const GTypeInfo id_info = {
52 			sizeof (ASGtkImageDirClass),
53 			(GBaseInitFunc) NULL,
54 			(GBaseFinalizeFunc) NULL,
55 			(GClassInitFunc) asgtk_image_dir_class_init,
56 			NULL,											/* class_finalize */
57 			NULL,											/* class_data     */
58 			sizeof (ASGtkImageDir),
59 			0,												/* n_preallocs    */
60 			(GInstanceInitFunc) asgtk_image_dir_init,
61 		};
62 
63 		id_type =
64 				g_type_register_static (GTK_TYPE_SCROLLED_WINDOW, "ASGtkImageDir",
65 																&id_info, 0);
66 	}
67 
68 	return id_type;
69 }
70 
asgtk_image_dir_class_init(ASGtkImageDirClass * klass)71 static void asgtk_image_dir_class_init (ASGtkImageDirClass * klass)
72 {
73 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
74 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
75 
76 	parent_class = g_type_class_peek_parent (klass);
77 
78 	object_class->dispose = asgtk_image_dir_dispose;
79 	object_class->finalize = asgtk_image_dir_finalize;
80 
81 	widget_class->style_set = asgtk_image_dir_style_set;
82 
83 }
84 
asgtk_image_dir_init(ASGtkImageDir * id)85 static void asgtk_image_dir_init (ASGtkImageDir * id)
86 {
87 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (id),
88 																	GTK_POLICY_AUTOMATIC,
89 																	GTK_POLICY_AUTOMATIC);
90 	id->flags = ASGTK_ImageDir_DefaultFlags;
91 	id->fulldirname = NULL;
92 	id->entries = NULL;
93 }
94 
asgtk_image_dir_dispose(GObject * object)95 static void asgtk_image_dir_dispose (GObject * object)
96 {
97 	ASGtkImageDir *id = ASGTK_IMAGE_DIR (object);
98 
99 	destroy_string (&(id->fulldirname));
100 	G_OBJECT_CLASS (parent_class)->dispose (object);
101 }
102 
asgtk_image_dir_finalize(GObject * object)103 static void asgtk_image_dir_finalize (GObject * object)
104 {
105 	G_OBJECT_CLASS (parent_class)->finalize (object);
106 }
107 
108 static void
asgtk_image_dir_style_set(GtkWidget * widget,GtkStyle * prev_style)109 asgtk_image_dir_style_set (GtkWidget * widget, GtkStyle * prev_style)
110 {
111 	/* ASGtkImageDir *id = ASGTK_IMAGE_DIR (widget); */
112 
113 	GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
114 }
115 
116 static void
asgtk_image_dir_sel_handler(GtkTreeSelection * selection,gpointer user_data)117 asgtk_image_dir_sel_handler (GtkTreeSelection * selection,
118 														 gpointer user_data)
119 {
120 	ASGtkImageDir *id = ASGTK_IMAGE_DIR (user_data);
121 	GtkTreeIter iter;
122 	GtkTreeModel *model;
123 
124 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
125 		gpointer p = NULL;
126 
127 		gtk_tree_model_get (model, &iter, ASGTK_ImageDir_Cols, &p, -1);
128 		id->curr_selection = (ASImageListEntry *) p;
129 	} else
130 		id->curr_selection = NULL;
131 
132 	if (id->sel_change_handler)
133 		id->sel_change_handler (id, id->sel_change_user_data);
134 }
135 
136 void
asgtk_image_dir2view_sel_handler(ASGtkImageDir * id,gpointer user_data)137 asgtk_image_dir2view_sel_handler (ASGtkImageDir * id, gpointer user_data)
138 {
139 	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (user_data);
140 
141 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
142 	if (iv)
143 		asgtk_image_view_set_entry (iv, id->curr_selection);
144 }
145 
146 
147 
148 /*  public functions  */
asgtk_image_dir_new()149 GtkWidget *asgtk_image_dir_new ()
150 {
151 	ASGtkImageDir *id;
152 	GtkTreeSelection *selection;
153 	const char *column_names[ASGTK_ImageDir_Cols] =
154 			{ "Name", "Type", "Size(KB)", "MTime", "Permission" };
155 	int i;
156 	int default_columns =
157 			ASGTK_ImageDir_DefaultFlags & ASGTK_ImageDir_Cols_All;
158 
159 	id = g_object_new (ASGTK_TYPE_IMAGE_DIR, NULL);
160 
161 	id->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
162 	id->tree_model =
163 			GTK_TREE_MODEL (gtk_list_store_new
164 											(ASGTK_ImageDir_Cols + 1, G_TYPE_STRING,
165 											 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
166 											 G_TYPE_STRING, G_TYPE_POINTER));
167 
168 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (id),
169 																			 GTK_SHADOW_IN);
170 
171 	gtk_container_add (GTK_CONTAINER (id), GTK_WIDGET (id->tree_view));
172 	gtk_tree_view_set_model (id->tree_view, id->tree_model);
173 	gtk_widget_show (GTK_WIDGET (id->tree_view));
174 	for (i = 0; i < ASGTK_ImageDir_Cols; ++i) {
175 		GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
176 
177 		id->columns[i] =
178 				gtk_tree_view_column_new_with_attributes (column_names[i],
179 																									renderer, "text", i,
180 																									NULL);
181 	}
182 	clear_flags (id->flags, ASGTK_ImageDir_Cols_All);
183 	asgtk_image_dir_set_columns (id, default_columns);
184 
185 	selection = gtk_tree_view_get_selection (id->tree_view);
186 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
187 	g_signal_connect (selection, "changed",
188 										G_CALLBACK (asgtk_image_dir_sel_handler), id);
189 
190 	colorize_gtk_tree_view_window (GTK_WIDGET (id));
191 
192 	LOCAL_DEBUG_OUT ("created image ASGtkImageDir object %p", id);
193 	return GTK_WIDGET (id);
194 }
195 
asgtk_image_dir_set_columns(ASGtkImageDir * id,ASFlagType columns)196 void asgtk_image_dir_set_columns (ASGtkImageDir * id, ASFlagType columns)
197 {
198 	int i;
199 
200 	for (i = 0; i < ASGTK_ImageDir_Cols; ++i) {
201 		ASFlagType flag = 0x01 << i;
202 
203 		if (get_flags (columns, flag)) {
204 			gtk_tree_view_insert_column (id->tree_view,
205 																	 GTK_TREE_VIEW_COLUMN (id->columns[i]),
206 																	 i);
207 			set_flags (id->flags, flag);
208 		} else if (get_flags (id->flags, flag)) {
209 			gtk_tree_view_remove_column (id->tree_view,
210 																	 GTK_TREE_VIEW_COLUMN (id->columns[i]));
211 			clear_flags (id->flags, flag);
212 		}
213 	}
214 }
215 
asgtk_image_dir_set_list_all(ASGtkImageDir * id,Bool enable)216 void asgtk_image_dir_set_list_all (ASGtkImageDir * id, Bool enable)
217 {
218 	if (enable && get_flags (id->flags, ASGTK_ImageDir_ListAll))
219 		return;
220 	if (!enable && !get_flags (id->flags, ASGTK_ImageDir_ListAll))
221 		return;
222 	if (enable)
223 		set_flags (id->flags, ASGTK_ImageDir_ListAll);
224 	else
225 		clear_flags (id->flags, ASGTK_ImageDir_ListAll);
226 
227 	asgtk_image_dir_refresh (id);
228 }
229 
230 
asgtk_image_dir_set_path(ASGtkImageDir * id,char * fulldirname)231 void asgtk_image_dir_set_path (ASGtkImageDir * id, char *fulldirname)
232 {
233 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
234 	LOCAL_DEBUG_OUT ("id->fulldirname == \"%s\", fulldirname == \"%s\"",
235 									 id->fulldirname, fulldirname);
236 	if (id->fulldirname == NULL && fulldirname == NULL)
237 		return;
238 	if (id->fulldirname && fulldirname
239 			&& strcmp (id->fulldirname, fulldirname) == 0)
240 		return;
241 	destroy_string (&(id->fulldirname));
242 
243 	if (fulldirname)
244 		id->fulldirname = mystrdup (fulldirname);
245 
246 	asgtk_image_dir_refresh (id);
247 }
248 
asgtk_image_dir_set_mini(ASGtkImageDir * id,char * mini_extension)249 void asgtk_image_dir_set_mini (ASGtkImageDir * id, char *mini_extension)
250 {
251 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
252 
253 	if (id->mini_extension == NULL && mini_extension == NULL)
254 		return;
255 	if (id->mini_extension && mini_extension
256 			&& strcmp (id->mini_extension, mini_extension) == 0)
257 		return;
258 	destroy_string (&(id->mini_extension));
259 
260 	if (mini_extension)
261 		id->mini_extension = mystrdup (mini_extension);
262 
263 	asgtk_image_dir_refresh (id);
264 }
265 
asgtk_image_dir_set_title(ASGtkImageDir * id,const gchar * title)266 void asgtk_image_dir_set_title (ASGtkImageDir * id, const gchar * title)
267 {
268 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
269 	gtk_tree_view_column_set_title (id->columns[0], title);
270 }
271 
272 void
asgtk_image_dir_set_sel_handler(ASGtkImageDir * id,_ASGtkImageDir_sel_handler sel_change_handler,gpointer user_data)273 asgtk_image_dir_set_sel_handler (ASGtkImageDir * id,
274 																 _ASGtkImageDir_sel_handler
275 																 sel_change_handler, gpointer user_data)
276 {
277 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
278 
279 	id->sel_change_handler = sel_change_handler;
280 	id->sel_change_user_data = user_data;
281 
282 }
283 
asgtk_image_dir_get_selection(ASGtkImageDir * id)284 struct ASImageListEntry *asgtk_image_dir_get_selection (ASGtkImageDir * id)
285 {
286 	ASImageListEntry *result = NULL;
287 
288 	if (ASGTK_IS_IMAGE_DIR (id))
289 		result = ref_asimage_list_entry (id->curr_selection);
290 
291 	return result;
292 }
293 
294 const char *as_image_file_type_names_short[ASIT_Unknown + 1] = {
295 	"XPM",
296 	"ZXPM",
297 	"GZXPM",
298 	"PNG",
299 	"JPEG",
300 	"GIMP",
301 	"PPM",
302 	"PNM",
303 	"BMP",
304 	"ICO",
305 	"MS CUR",
306 	"GIF",
307 	"TIFF",
308 	"AS XML",
309 	"SVG",
310 	"XBM",
311 	"Targa",
312 	"PCX",
313 	"HTML",
314 	"XML",
315 	""
316 };
317 
318 
asgtk_image_dir_refresh(ASGtkImageDir * id)319 void asgtk_image_dir_refresh (ASGtkImageDir * id)
320 {
321 	int items = 0;
322 	char *curr_sel;
323 
324 	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
325 
326 	curr_sel = mystrdup (id->curr_selection ? id->curr_selection->name : "");
327 
328 	gtk_list_store_clear (GTK_LIST_STORE (id->tree_model));
329 	destroy_asimage_list (&(id->entries));
330 	id->curr_selection = NULL;
331 	if (id->fulldirname) {
332 		unsigned int count;
333 		GtkTreeIter iter;
334 		ASImageListEntry *curr;
335 		int mini_ext_len =
336 				id->mini_extension ? strlen (id->mini_extension) : 0;
337 
338 		id->entries =
339 				get_asimage_list (get_screen_visual (NULL), id->fulldirname, 0,
340 													get_screen_image_manager (NULL)->gamma, 0, 0, 0,
341 													&count, NULL);
342 
343 		curr = id->entries;
344 		while (curr) {
345 			Bool mini = False;
346 
347 			LOCAL_DEBUG_OUT ("adding item \"%s\"", curr->name);
348 			if (mini_ext_len > 1) {
349 				if (id->mini_extension[mini_ext_len - 1] == '.')
350 					mini =
351 							(strncmp (curr->name, id->mini_extension, mini_ext_len) ==
352 							 0);
353 				else {
354 					int name_len = strlen (curr->name);
355 
356 					if (name_len > mini_ext_len)
357 						mini =
358 								(strncmp
359 								 (&(curr->name[name_len - mini_ext_len]),
360 									id->mini_extension, mini_ext_len) == 0);
361 				}
362 			}
363 			if ((!mini && curr->type <= ASIT_Supported)
364 					|| get_flags (id->flags, ASGTK_ImageDir_ListAll)) {
365 				char size_str[64];
366 				char date_str[32];
367 				struct tm *mt = gmtime (&(curr->d_mtime));
368 
369 				sprintf (date_str, "%02d-%02d-%02d %02d:%02d",
370 								 (mt->tm_year + 1900) % 100, mt->tm_mon + 1, mt->tm_mday,
371 								 mt->tm_hour, mt->tm_min);
372 				sprintf (size_str, "%lu",
373 								 (unsigned long)((curr->d_size + 1023) / 1024));
374 
375 				gtk_list_store_append (GTK_LIST_STORE (id->tree_model), &iter);
376 				gtk_list_store_set (GTK_LIST_STORE (id->tree_model), &iter,
377 														ASGTK_ImageDir_Col_Name_No, curr->name,
378 														ASGTK_ImageDir_Col_Type_No,
379 														as_image_file_type_names_short[curr->type],
380 														ASGTK_ImageDir_Col_Size_No, size_str,
381 														ASGTK_ImageDir_Col_Date_No, date_str,
382 														ASGTK_ImageDir_Cols, curr, -1);
383 				if (++items == 1)
384 					gtk_tree_selection_select_iter (gtk_tree_view_get_selection
385 																					(id->tree_view), &iter);
386 				else if (strcmp (curr->name, curr_sel) == 0)
387 					gtk_tree_selection_select_iter (gtk_tree_view_get_selection
388 																					(id->tree_view), &iter);
389 			}
390 			curr = curr->next;
391 		}
392 		/*
393 		   :sG:
394 		   The following 3 lines make the file lists sorted by
395 		   the File Name, Ascending.
396 
397 		   For general file listing (not dirs)
398 		 */
399 		GtkTreeSortable *sortable;
400 
401 		sortable = GTK_TREE_SORTABLE (id->tree_model);
402 		gtk_tree_sortable_set_sort_column_id (sortable,
403 																					ASGTK_ImageDir_Col_Name_No,
404 																					GTK_SORT_ASCENDING);
405 	}
406 	if (curr_sel)
407 		free (curr_sel);
408 	if (items == 0) {
409 		asgtk_image_dir_sel_handler (gtk_tree_view_get_selection
410 																 (id->tree_view), id);
411 	}
412 }
413 
414 Bool
asgtk_image_dir_make_mini_names(ASGtkImageDir * id,const char * name,char ** name_return,char ** fullname_return)415 asgtk_image_dir_make_mini_names (ASGtkImageDir * id, const char *name,
416 																 char **name_return,
417 																 char **fullname_return)
418 {
419 	if (id->mini_extension && name) {
420 		int mini_ext_len = strlen (id->mini_extension);
421 		char *mini_filename = safemalloc (strlen (name) + mini_ext_len + 1);
422 
423 		if (id->mini_extension[mini_ext_len - 1] == '.')
424 			sprintf (mini_filename, "%s%s", id->mini_extension, name);
425 		else
426 			sprintf (mini_filename, "%s%s", name, id->mini_extension);
427 
428 		if (fullname_return)
429 			*fullname_return = make_file_name (id->fulldirname, mini_filename);
430 
431 		if (name_return)
432 			*name_return = mini_filename;
433 		else
434 			free (mini_filename);
435 		return True;
436 	}
437 	return False;
438 
439 }
440 
open_xml_file_in_dir(ASGtkImageDir * id,const char * name,Bool mini)441 FILE *open_xml_file_in_dir (ASGtkImageDir * id, const char *name,
442 														Bool mini)
443 {
444 	FILE *fp = NULL;
445 	char *fullfilename = NULL;
446 
447 	return NULL;
448 	if (mini) {
449 		if (!asgtk_image_dir_make_mini_names (id, name, NULL, &fullfilename))
450 			return NULL;
451 	} else
452 		fullfilename = make_file_name (id->fulldirname, name);
453 
454 	if (CheckFile (fullfilename) == 0) {
455 		if (!mini)
456 			if (!asgtk_yes_no_question1
457 					(NULL,
458 					 "It appears that you already have private background with name \"%s\". Would you like to overwrite it ?",
459 					 name)) {
460 				free (fullfilename);
461 				return NULL;
462 			}
463 		unlink (fullfilename);
464 	}
465 	fp = fopen (fullfilename, "w");
466 	if (fp == NULL)
467 		asgtk_warning2 (NULL, "Failed to open file \"%s\" : %s.", fullfilename,
468 										g_strerror (errno));
469 
470 	free (fullfilename);
471 	return fp;
472 
473 }
474 
475 Bool
make_xml_from_string(ASGtkImageDir * id,const char * name,const char * str,Bool mini)476 make_xml_from_string (ASGtkImageDir * id, const char *name,
477 											const char *str, Bool mini)
478 {
479 	FILE *fp;
480 
481 	if (name == NULL || str == NULL)
482 		return False;
483 
484 	if ((fp = open_xml_file_in_dir (id, name, mini)) == NULL)
485 		return False;
486 
487 	fprintf (fp, "%s\n", str);
488 	fclose (fp);
489 
490 	return True;
491 }
492 
493 Bool
make_mini_for_image_entry(ASGtkImageDir * id,ASImageListEntry * entry,const char * mini_fullfilename)494 make_mini_for_image_entry (ASGtkImageDir * id, ASImageListEntry * entry,
495 													 const char *mini_fullfilename)
496 {
497 	Bool res = False;
498 
499 	if (entry->type == ASIT_XMLScript) {
500 		char *xml = safemalloc (128 + strlen (entry->name));
501 
502 		sprintf (xml,
503 						 "<scale width=\"$minipixmap.width\" height=\"$minipixmap.height\"><img src=\"%s\"/></scale>",
504 						 entry->name);
505 		res = make_xml_from_string (id, entry->name, xml, True);
506 		free (xml);
507 	} else if (entry->preview) {
508 		ASImage *thumbnail =
509 				scale_asimage (get_screen_visual (NULL), entry->preview, 24, 24,
510 											 ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
511 		if (thumbnail) {
512 			res =
513 					save_asimage_to_file (mini_fullfilename, thumbnail, "png", "9",
514 																NULL, 0, True);
515 			destroy_asimage (&thumbnail);
516 		}
517 	}
518 	return res;
519 }
520