1 /*
2 * previews.c: Pixmap preview browser
3 *
4 * Written by: Ullrich Hafner
5 *
6 * Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21 */
22
23 /*
24 * $Date: 1999/10/23 17:44:29 $
25 * $Author: hafner $
26 * $Revision: 1.30 $
27 * $State: Exp $
28 */
29
30 #include "config.h"
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
39 #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
40 # include <dirent.h>
41 # define NLENGTH(dirent) (strlen ((dirent)->d_name))
42 #else
43 # define dirent direct
44 # define NLENGTH(dirent) ((dirent)->d_namlen)
45 # ifdef HAVE_SYS_NDIR_H
46 # include <sys/ndir.h>
47 # endif /* HAVE_SYS_NDIR_H */
48 # ifdef HAVE_SYS_DIR_H
49 # include <sys/dir.h>
50 # endif /* HAVE_SYS_DIR_H */
51 # ifdef HAVE_NDIR_H
52 # include <ndir.h>
53 # endif /* HAVE_NDIR_H */
54 #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
55
56 #include <gtk/gtk.h>
57 #include "proplist_t.h"
58
59 #include "previews.h"
60 #include "window.h"
61 #include "misc.h"
62 #include "dialog.h"
63 #include "texture.h"
64
65 #include "error.h"
66
67 /*******************************************************************************
68
69 global variables
70
71 *******************************************************************************/
72
73 extern GtkTooltips *tooltips;
74 extern proplist_t windowmaker; /* window.c */
75
76 /*******************************************************************************
77
78 local variables
79
80 *******************************************************************************/
81
82 static GList *file_list = NULL;
83 static GtkWidget *table = NULL;
84 static GtkWidget *entry = NULL;
85 static GtkWidget *main_vbox = NULL;
86 static GtkWidget *scrolled = NULL;
87 static GtkWidget *ok_button = NULL;
88 static wtexture_t *wtexture = NULL;
89 static GtkWidget *pathomenu = NULL;
90 static GtkWidget *previewbutton = NULL;
91
92 /*******************************************************************************
93
94 prototypes
95
96 *******************************************************************************/
97
98 static void
99 unlock_filelist (GtkWidget *widget, gpointer ptr);
100 static void
101 lock_filelist (GtkWidget *widget, gpointer ptr);
102 static void
103 new_scrolled_and_table (void);
104 static void
105 destroy_data (gpointer data, gpointer user_data);
106 static void
107 preview_new_path (GtkWidget *widget, gpointer ptr);
108 static void
109 image_list (const char *path);
110 static void
111 make_preview (GtkWidget *entry, char *name);
112 static gint
113 set_selection (GtkWidget *widget, GdkEventButton *event, gpointer ptr);
114 static void
115 accept_selection (GtkWidget *widget, gpointer ptr);
116 static void
117 show_previews (GtkWidget *table);
118
119 /*******************************************************************************
120
121 public code
122
123 *******************************************************************************/
124
125 void
preview_browser(GtkWidget * widget,gpointer ptr)126 preview_browser (GtkWidget *widget, gpointer ptr)
127 /*
128 * Open or close pixmap preview image browser dialog window.
129 * If the window is visible then hide the window and vice versa.
130 *
131 * No return value.
132 */
133 {
134 static GtkWidget *window= NULL;
135
136 wtexture = (wtexture_t *) ptr;
137 if (!window) /* window already created */
138 {
139 entry = gtk_entry_new ();
140
141 /*
142 * Make new dialog window
143 */
144 window = gtk_dialog_new ();
145 gtk_window_set_title (GTK_WINDOW (window), _("Pixmap Browser"));
146 gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
147 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
148 GTK_SIGNAL_FUNC (gtk_true), NULL);
149 gtk_signal_connect_object (GTK_OBJECT (window), "delete_event",
150 GTK_SIGNAL_FUNC (gtk_widget_hide),
151 GTK_OBJECT (window));
152
153 /*
154 * Optionmenu pixmap path and update button
155 */
156 {
157 const char **pathlist;
158 unsigned n;
159 GtkWidget *box;
160 GtkWidget *button = gtk_button_new_with_label (_("Update previews"));
161 GtkWidget *bbox = gtk_hbutton_box_new ();
162 GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
163 proplist_t plpath = WMCreatePLString ("PixmapPath");
164 proplist_t pixmap_path = WMGetFromPLDictionary (windowmaker, plpath);
165
166 gtk_signal_connect (GTK_OBJECT (button), "clicked",
167 GTK_SIGNAL_FUNC (lock_filelist), &file_list);
168 gtk_signal_connect (GTK_OBJECT (button), "clicked",
169 GTK_SIGNAL_FUNC (generate_previews), &file_list);
170 gtk_signal_connect (GTK_OBJECT (button), "clicked",
171 GTK_SIGNAL_FUNC (unlock_filelist), &file_list);
172
173 WMReleasePropList (plpath);
174 pathlist = Calloc (WMGetPropListItemCount (pixmap_path) + 1,
175 sizeof (char *));
176
177 for (n = 0; n < WMGetPropListItemCount (pixmap_path); n++)
178 pathlist [n] = WMGetFromPLString (WMGetFromPLArray (pixmap_path, n));
179 pathlist [n] = NULL;
180
181 box = generate_option_menu (NULL, tooltips,
182 _("Window Maker's searchpath for pixmaps"),
183 pathlist, pathlist [0], NULL,
184 preview_new_path, NULL);
185 image_list (pathlist [0]);
186 Free (pathlist);
187
188 pathomenu = box;
189 previewbutton = button;
190
191 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
192 hbox, FALSE, TRUE, 5);
193 gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new ("PixmapPath:"),
194 FALSE, TRUE, 5);
195 gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, TRUE, 5);
196 gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, TRUE, 5);
197 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 0);
198 }
199 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
200 main_vbox = gtk_vbox_new (FALSE, 0), TRUE, TRUE, 5);
201 new_scrolled_and_table ();
202 /*
203 * Confirm arean (at bottom)
204 */
205 {
206 GtkWidget *confirm_area;
207 GtkWidget *button;
208 GtkWidget *hbox;
209
210 hbox = gtk_hbox_new (FALSE, 5);
211 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox,
212 FALSE, TRUE, 0);
213
214 gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Filename:")),
215 FALSE, TRUE, 0);
216
217 gtk_widget_set_usize (entry, 200, 0);
218 gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
219 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 10);
220
221 confirm_area = gtk_hbutton_box_new ();
222 gtk_box_pack_end (GTK_BOX (hbox), confirm_area, FALSE, TRUE, 10);
223 gtk_button_box_set_spacing (GTK_BUTTON_BOX (confirm_area), 5);
224 gtk_button_box_set_layout (GTK_BUTTON_BOX (confirm_area),
225 GTK_BUTTONBOX_END);
226
227 ok_button = gtk_button_new_with_label (_("OK"));
228 gtk_box_pack_start (GTK_BOX (confirm_area), ok_button, TRUE, TRUE, 0);
229 gtk_signal_connect (GTK_OBJECT (ok_button), "clicked",
230 GTK_SIGNAL_FUNC (accept_selection), NULL);
231 gtk_entry_set_text (GTK_ENTRY (entry), PKGDATADIR "/black.xpm");
232 GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
233 gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked",
234 GTK_SIGNAL_FUNC (gtk_widget_hide),
235 GTK_OBJECT (window));
236
237 button = gtk_button_new_with_label (_("Cancel"));
238 gtk_box_pack_start (GTK_BOX (confirm_area), button, TRUE, TRUE, 0);
239 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
240 GTK_SIGNAL_FUNC (gtk_widget_hide),
241 GTK_OBJECT (window));
242 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
243 gtk_widget_grab_default (button);
244 }
245 show_previews (table);
246 }
247
248 if (!GTK_WIDGET_VISIBLE (window))
249 gtk_widget_show_all (window);
250 else
251 gtk_widget_hide (window);
252 }
253
254 static void
image_list(const char * path)255 image_list (const char *path)
256 {
257 DIR *dir;
258 struct dirent *file;
259 char *realpath = expand_tilde (path);
260
261 dir = opendir (realpath);
262 if (!dir)
263 return;
264 while ((file = readdir (dir)))
265 {
266 if (streq (file->d_name, ".") || streq (file->d_name, ".."))
267 continue;
268 /*
269 * Check whether file is a directory
270 */
271 {
272 char *subdir = g_strconcat (realpath, "/", file->d_name, NULL);
273 DIR *tmpdir = opendir (subdir);
274
275 if (tmpdir)
276 {
277 closedir (tmpdir);
278 Free (subdir);
279 continue;
280 }
281 make_preview (entry, subdir);
282 }
283 }
284 Free (realpath);
285 closedir (dir);
286 }
287
288 static void
make_preview(GtkWidget * entry,char * name)289 make_preview (GtkWidget *entry, char *name)
290 /*
291 * Make button widget displaying a pixmap with tooltips showing the
292 * pixmap filename.
293 * 'image' is the filename of the preview.
294 *
295 * Return value:
296 * button widget
297 */
298 {
299 previewdata_t *data = Calloc (1, sizeof (previewdata_t));
300 GtkWidget *pixmap;
301
302 data->name = name;
303 data->button = gtk_button_new ();
304
305 gtk_signal_connect (GTK_OBJECT (data->button), "button_press_event",
306 GTK_SIGNAL_FUNC (set_selection), data);
307 file_list = g_list_append (file_list, data);
308
309 {
310 char *fname = expand_tilde (name);
311 char *pname = preview_name (fname);
312 char *path = get_pixmap_path (pname);
313
314 if (path)
315 {
316 pixmap = make_pixmap (path, 64, 64, NULL);
317 Free (path);
318 }
319 else
320 {
321 pixmap = make_pixmap (PKGDATADIR "/black.xpm", 64, 64, NULL);
322 make_pixmap (WMAKERDATADIR "/Icons/defaultAppIcon.xpm", 64, 64, pixmap);
323 }
324
325 Free (fname);
326 Free (pname);
327 }
328
329 gtk_tooltips_set_tip (tooltips, data->button, g_path_get_basename (name), NULL);
330 gtk_container_set_border_width (GTK_CONTAINER (data->button), 2);
331 gtk_container_add (GTK_CONTAINER (data->button), pixmap);
332 gtk_widget_show_all (data->button);
333 gtk_object_set_user_data (GTK_OBJECT (data->button), pixmap);
334 gtk_object_set_user_data (GTK_OBJECT (pixmap), entry);
335 }
336
337 static gint
set_selection(GtkWidget * widget,GdkEventButton * event,gpointer ptr)338 set_selection (GtkWidget *widget, GdkEventButton *event, gpointer ptr)
339 /*
340 * Change text entry if pixmap button is pressed.
341 */
342 {
343 GtkWidget *pixmap = gtk_object_get_user_data (GTK_OBJECT (widget));
344 GtkWidget *entry = gtk_object_get_user_data (GTK_OBJECT (pixmap));
345 previewdata_t *data = (previewdata_t *) ptr;
346
347 gtk_entry_set_text (GTK_ENTRY (entry), g_path_get_basename (data->name));
348
349 if (event->type == GDK_2BUTTON_PRESS)
350 gtk_signal_emit_by_name (GTK_OBJECT (ok_button), "clicked");
351
352 return TRUE;
353 }
354
355 static void
accept_selection(GtkWidget * widget,gpointer ptr)356 accept_selection (GtkWidget *widget, gpointer ptr)
357 /*
358 * OK button is activated: set pixmap and text entry of texture dialog.
359 *
360 * No return value.
361 */
362 {
363 gtk_entry_set_text (GTK_ENTRY (wtexture->wpixmap [PIXMAP_NAME]),
364 gtk_entry_get_text (GTK_ENTRY (entry)));
365 verify_pixmap_name (entry, wtexture);
366 }
367
368 static void
show_previews(GtkWidget * table)369 show_previews (GtkWidget *table)
370 {
371 unsigned n = 0;
372 unsigned x = 0;
373 unsigned y = 0;
374
375 for (n = 0; n < g_list_length (file_list); n++)
376 {
377 previewdata_t *data = g_list_nth_data (file_list, n);
378
379 gtk_table_attach (GTK_TABLE (table), data->button, x, x + 1, y, y + 1,
380 GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
381 x++;
382 if (x == 8)
383 {
384 x = 0;
385 y++;
386 }
387 }
388 }
389
390 static void
preview_new_path(GtkWidget * widget,gpointer ptr)391 preview_new_path (GtkWidget *widget, gpointer ptr)
392 {
393 char *text = gtk_object_get_user_data (GTK_OBJECT (widget));
394
395 g_list_foreach (file_list, destroy_data, NULL);
396 g_list_free (file_list);
397 file_list = NULL;
398 new_scrolled_and_table ();
399 image_list (text);
400 show_previews (table);
401 }
402
403 static void
destroy_data(gpointer data,gpointer user_data)404 destroy_data (gpointer data, gpointer user_data)
405 {
406 previewdata_t *pd = (previewdata_t *) data;
407
408 Free (pd->name);
409 Free (pd);
410 }
411
412 static void
new_scrolled_and_table(void)413 new_scrolled_and_table (void)
414 {
415 if (scrolled)
416 gtk_widget_destroy (scrolled);
417 scrolled = gtk_scrolled_window_new (NULL, NULL);
418 gtk_box_pack_start (GTK_BOX (main_vbox), scrolled, TRUE, TRUE, 5);
419
420 table = gtk_table_new (1, 1, TRUE);
421 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
422 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
423 gtk_widget_set_usize (scrolled, 660, 430);
424 gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5);
425
426 gtk_container_set_border_width (GTK_CONTAINER (table), 5);
427 gtk_table_set_row_spacings (GTK_TABLE (table), 2);
428 gtk_table_set_col_spacings (GTK_TABLE (table), 2);
429 gtk_widget_show (table);
430 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
431 table);
432 gtk_widget_show_all (scrolled);
433 }
434
435 static void
lock_filelist(GtkWidget * widget,gpointer ptr)436 lock_filelist (GtkWidget *widget, gpointer ptr)
437 {
438 gtk_widget_set_sensitive (pathomenu, FALSE);
439 gtk_widget_set_sensitive (previewbutton, FALSE);
440 }
441
442 static void
unlock_filelist(GtkWidget * widget,gpointer ptr)443 unlock_filelist (GtkWidget *widget, gpointer ptr)
444 {
445 gtk_widget_set_sensitive (pathomenu, TRUE);
446 gtk_widget_set_sensitive (previewbutton, TRUE);
447 }
448
449