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