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