1 /*
2  *  window.c:		GTK stuff
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 /*
25  *  $Date: 2000/09/03 19:22:06 $
26  *  $Author: hafner $
27  *  $Revision: 1.123 $
28  *  $State: Exp $
29  */
30 
31 #include "config.h"
32 
33 #if HAVE_STDLIB_H
34 #	include <stdlib.h>
35 #endif /* not HAVE_STDLIB_H */
36 #if HAVE_STRING_H
37 #	include <string.h>
38 #else /* not HAVE_STRING_H */
39 #	include <strings.h>
40 #endif /* not HAVE_STRING_H */
41 #if HAVE_SYS_STAT_H
42 #	include <sys/stat.h>
43 #endif /* HAVE_SYS_STAT_H */
44 
45 #include <stdio.h>
46 #include <gtk/gtk.h>
47 #include "proplist_t.h"
48 
49 /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
50 #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
51 #   include <dirent.h>
52 #   define NLENGTH(dirent) (strlen ((dirent)->d_name))
53 #else
54 #   define dirent direct
55 #   define NLENGTH(dirent) ((dirent)->d_namlen)
56 #   ifdef HAVE_SYS_NDIR_H
57 #       include <sys/ndir.h>
58 #   endif /* HAVE_SYS_NDIR_H */
59 #   ifdef HAVE_SYS_DIR_H
60 #       include <sys/dir.h>
61 #   endif /* HAVE_SYS_DIR_H */
62 #   ifdef HAVE_NDIR_H
63 #       include <ndir.h>
64 #   endif /* HAVE_NDIR_H */
65 #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
66 
67 #ifdef HAVE_IMLIB
68 #include <gdk_imlib.h>
69 #endif /* HAVE_IMLIB */
70 
71 #include "window.h"
72 #include "icons.h"
73 #include "misc.h"
74 #include "dialog.h"
75 #include "texture.h"
76 #include "keys.h"
77 #include "menu.h"
78 #include "shortcuts.h"
79 #include "rootmenu.h"
80 #include "simple.h"
81 #include "path.h"
82 #include "themebrowser.h"
83 #include "rimage.h"
84 
85 #include "error.h"
86 
87 /*****************************************************************************
88 
89 			     global variables
90 
91 *****************************************************************************/
92 
93 bool_t	     changed     = NO;
94 bool_t	     use_imlib   = NO;
95 GtkWidget   *main_window = NULL;
96 GdkColor    *background  = NULL;
97 GtkTooltips *tooltips    = NULL;
98 proplist_t   windowmaker = NULL;
99 proplist_t   wmconfig    = NULL;
100 
101 extern char       *orig_wmaker_fname;
102 extern proplist_t  plist_changed;
103 extern proplist_t  pl_yes;
104 
105 GtkWidget *widgetstyle_item = NULL;
106 
107 /*****************************************************************************
108 
109 			       prototypes
110 
111 *****************************************************************************/
112 
113 void
114 update (gpointer ptr, proplist_t value);
115 static GtkWidget *
116 create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
117 	     bool_t horizontal);
118 static void
119 quit_and_save_popup (char *question,
120 		     void (*yes_function) (GtkWidget *, gpointer),
121 		     gpointer dataptr);
122 static void
123 switch_subentries (GtkWidget *widget, gpointer ptr);
124 static void
125 init_option_menu (gpointer data, gpointer user_data);
126 static void
127 appearance_container (proplist_t type, proplist_t thispanel,
128 		      GList **options, GtkWidget *box);
129 static int
130 compare_fn (const void * p1, const void * p2);
131 
132 typedef struct { char * name; char * intlname; } names_t;
133 
134 /*****************************************************************************
135 
136 			       public code
137 
138 *****************************************************************************/
139 
140 void
root_window(const char * conffile,const node * sections,int sections_restriction_type,bool_t noinet,GtkWidget * logwindow,proplist_t wmc,proplist_t panel,proplist_t wmlist)141 root_window (const char *conffile, const node *sections,
142 	     int sections_restriction_type, bool_t noinet,
143 	     GtkWidget *logwindow,  proplist_t wmc,
144 	     proplist_t panel, proplist_t wmlist)
145 /*
146  *  Create root window and call the event loop of GTK
147  *
148  *  No return value.
149  */
150 {
151    GtkWidget  *box1;
152    GtkWidget  *notebook;
153 #ifndef FREEBSD_SYSTEM
154    GtkWidget  *progress_window = NULL;
155    GtkWidget  *progress_label  = NULL;
156    GtkWidget  *progress_bar    = NULL;
157 #endif /* not FREEBSD_SYSTEM */
158    GtkWidget  *toolbar;
159    proplist_t  plinfo          = WMCreatePLString ("Info");
160    proplist_t  pltype          = WMCreatePLString ("Type");
161    proplist_t  plicon          = WMCreatePLString ("Icon");
162    proplist_t  pltitle         = WMCreatePLString ("Title");
163    proplist_t  plwidget        = WMCreatePLString ("Widget");
164    proplist_t  plcolor         = WMCreatePLString ("Colorbox");
165    proplist_t  plfont          = WMCreatePLString ("Fontbox");
166    proplist_t  pltexture       = WMCreatePLString ("Texturebox");
167    proplist_t  plgrp           = WMCreatePLString ("Group");
168    proplist_t  plrange         = WMCreatePLString ("Range");
169    proplist_t  plrinfo         = WMCreatePLString ("RangeInfo");
170    GList      *options	       = NULL;
171    bool_t      section_found   = NO;
172    GtkWidget  *iconbox 	       = gtk_hbox_new (FALSE, 0);
173    char       *section 	       = NULL;      /* will point to something if only
174 					       one section will be shown*/
175 
176 
177 #if defined(PREVIEWS) && !defined(CONVERT)
178    init_wraster_lib ();
179 #endif /* defined(PREVIEWS) && !defined(CONVERT) */
180 
181    windowmaker = wmlist;
182    wmconfig    = wmc;
183 
184    if (sections_restriction_type == 1 && sections && !sections->next)
185       section = sections->name;
186 
187    /*
188     *  Progress bar window (only if not on FreeBSD and section is not given)
189     */
190 #ifndef FREEBSD_SYSTEM
191    if (!section)
192    {
193       GtkWidget *vbox;
194 
195       progress_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
196       gtk_window_set_title (GTK_WINDOW (progress_window),
197 			    PACKAGE " " VERSION " init ...");
198 
199       gtk_container_set_border_width (GTK_CONTAINER (progress_window), 10);
200       gtk_signal_connect (GTK_OBJECT (progress_window), "delete_event",
201 			  GTK_SIGNAL_FUNC (gtk_true), NULL);
202       gtk_widget_set_usize (progress_window, 250, -1);
203 
204       vbox = gtk_vbox_new (FALSE, 0);
205       gtk_container_add (GTK_CONTAINER (progress_window), vbox);
206 
207       progress_label = gtk_label_new ("");
208       gtk_box_pack_start (GTK_BOX (vbox), progress_label, FALSE, TRUE, 0);
209 
210       {
211 	 GtkAdjustment *adj;
212 
213 	 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 300, 0, 0, 0);
214 
215 	 progress_bar = gtk_progress_bar_new_with_adjustment (adj);
216 	 gtk_progress_set_format_string (GTK_PROGRESS (progress_bar), "[%p%%]");
217 	 gtk_progress_set_show_text (GTK_PROGRESS (progress_bar), YES);
218       }
219 
220       gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 0);
221       gtk_widget_show_all (progress_window);
222    }
223 #endif /* not FREEBSD_SYSTEM */
224 
225    /*
226     *  Fallback if libwraster is not (correctly) installed
227     */
228 #ifdef HAVE_IMLIB
229    {
230       GdkVisual		*gdkvisual;
231       GdkColormap	*gdkcmap;
232 
233       gdk_imlib_init ();
234       gdkvisual = gdk_imlib_get_visual ();
235       gdkcmap   = gdk_imlib_get_colormap ();
236 
237       if (gdkvisual && gdkcmap)
238       {
239 	 gtk_widget_push_visual (gdkvisual);
240 	 gtk_widget_push_colormap (gdkcmap);
241 	 use_imlib = YES;
242       }
243       else
244 	 use_imlib = NO;
245    }
246 #endif /* HAVE_IMLIB */
247 
248    gtk_widget_push_visual (gdk_rgb_get_visual ());
249    gtk_widget_push_colormap (gdk_rgb_get_cmap ());
250 
251    /*
252     *  Main window
253     */
254    main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
255    gtk_signal_connect (GTK_OBJECT (main_window), "delete_event",
256 		       GTK_SIGNAL_FUNC (quit), NULL);
257    gtk_widget_realize (main_window);
258    background = &main_window->style->bg [GTK_STATE_NORMAL];
259 
260    init_pixmaps ();
261 
262    while (gtk_events_pending())		/* FreeBSD workaround */
263       gtk_main_iteration();
264 
265    box1 = gtk_vbox_new (FALSE, 0);
266    gtk_container_add (GTK_CONTAINER (main_window), box1);
267    tooltips = gtk_tooltips_new ();
268    gtk_widget_show (box1);
269 
270    while (gtk_events_pending())		/* FreeBSD workaround */
271       gtk_main_iteration();
272 
273    /*
274     *  Menu and toolbox
275     */
276    gtk_box_pack_start (GTK_BOX(box1),
277 		       make_menubar (logwindow, section == NULL, noinet),
278 		       FALSE, TRUE, 0);
279    if (section)
280    {
281       gtk_box_pack_start (GTK_BOX(box1), iconbox, FALSE, TRUE, 0);
282       gtk_box_pack_start (GTK_BOX(iconbox), toolbar = make_toolbar (noinet),
283 			  FALSE, TRUE, 0);
284    }
285    else
286       gtk_box_pack_start (GTK_BOX(box1), toolbar = make_toolbar (noinet),
287 			  FALSE, TRUE, 0);
288 
289    while (gtk_events_pending())		/* FreeBSD workaround */
290       gtk_main_iteration();
291 
292    /*
293     *  Notebook for all different wmakerconf sections
294     */
295    notebook = gtk_notebook_new ();
296    gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (notebook), FALSE);
297    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), TRUE);
298    gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
299    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
300    gtk_box_pack_start (GTK_BOX (box1), notebook, TRUE, TRUE, 0);
301    gtk_container_set_border_width (GTK_CONTAINER (notebook), section ? 5 : 10);
302    gtk_widget_show_all (notebook);
303 
304    while (gtk_events_pending())		/* FreeBSD workaround */
305       gtk_main_iteration();
306 
307    /*
308     *  Generate notebook page for every section.
309     *  Section information is extracted from config file 'WMWmakerconf'.
310     */
311    {
312       proplist_t  tab_orig = WMGetPLDictionaryKeys (panel);
313       proplist_t  tab      = WMCreatePLArray (NULL);
314       names_t    *tab_s;
315       unsigned	  n;
316       int         size     = WMGetPropListItemCount (tab_orig);
317 
318       /* Sort the tabs alphabetically by the current translation.
319        * (OK, technically this isn't quite correct since the compare
320        * function is strcmp and the text ought to be UTF-8...)
321        * Unfortunately libWINGs provides no convenient way to do this. */
322       tab_s = malloc (size * sizeof (names_t));
323       for (n = 0; n < size; n++) {
324         proplist_t thispanel = WMGetFromPLArray (tab_orig, n);
325         proplist_t entry     = WMGetFromPLDictionary (panel, thispanel);
326         proplist_t info      = WMGetFromPLDictionary (entry, plinfo);
327 
328         tab_s[n].name        = WMGetFromPLString (thispanel);
329         tab_s[n].intlname    = D_(WMGetFromPLString(info));
330       }
331       qsort (tab_s, size, sizeof (names_t), compare_fn);
332       for (n = 0; n < size; n++)
333         WMAddToPLArray (tab, WMCreatePLString (tab_s[n].name));
334       free (tab_s);
335       WMReleasePropList (tab_orig);
336 
337       for (n = 0; n < size; n++)
338       {
339 	 proplist_t thispanel = WMGetFromPLArray (tab, n);
340 	 proplist_t entry     = WMGetFromPLDictionary (panel, thispanel);
341 	 proplist_t info      = WMGetFromPLDictionary (entry, plinfo);
342 	 proplist_t icon      = WMGetFromPLDictionary (entry, plicon);
343 	 proplist_t type      = WMGetFromPLDictionary (entry, pltype);
344 	 GtkWidget  *page;
345 
346 	 if (!icon || !info || !WMIsPLString (info) || !WMIsPLString (icon))
347 	    error (_("'%s': parse error."), conffile);
348 
349 	 /*
350 	  *  Check whether the current section is allowed
351 	  */
352 	 {
353 	    char       *thissecname = WMGetFromPLString (thispanel);
354 	    const node *cur;
355 	    bool_t 	matches;
356 
357 	    for (cur = sections, matches = NO; cur && !matches; cur = cur->next)
358 	       if (strcaseeq (thissecname, cur->name))
359 		  matches = YES;
360 
361 	    if (sections &&
362 		((matches && sections_restriction_type==NO)
363 		 || (!matches && sections_restriction_type==YES)))
364 		  continue;
365 	    /* we are here since this section is allowed */
366 	    section_found = TRUE;
367 	 }
368 
369 	 /*
370 	  *  Create new notbook page (use icon given in WMWmakerconf)
371 	  */
372 	 {
373 	    char *path = g_strconcat (PKGDATADIR, "/", WMGetFromPLString (icon), NULL);
374 
375 	    page = create_page (GTK_NOTEBOOK (notebook), D_(WMGetFromPLString (info)),
376 				path, TRUE);
377 	    Free (path);
378 	 }
379 
380 	 while (gtk_events_pending())		/* FreeBSD workaround */
381 	    gtk_main_iteration();
382 
383 	 /*
384 	  *  Create container for config widgets
385 	  */
386 	 {
387 	    GtkWidget  *box = gtk_vbox_new (FALSE, 5);
388 
389 	    gtk_widget_show (box);
390 
391 	    while (gtk_events_pending())		/* FreeBSD workaround */
392 	       gtk_main_iteration();
393 
394 	    /*
395 	     *  Use different layout if section is given:
396 	     *  Notebook border and tabs are invisible, section icon is
397 	     *  shown in the top right corner.
398 	     */
399 	    if (section)
400 	    {
401 	       GdkPixmap *pixmap;
402 	       GdkBitmap *mask;
403 	       GtkWidget *image;
404 	       GtkWidget *hbox 	= gtk_hbox_new (FALSE, 0);
405 	       char 	 *path 	= g_strconcat (PKGDATADIR, "/",
406 					       WMGetFromPLString (icon), NULL);
407 
408 	       pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
409 						    background, path);
410 	       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
411 	       gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
412 	       image  = gtk_pixmap_new (pixmap, mask);
413 	       gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
414 	       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
415 	       gtk_box_pack_end (GTK_BOX(iconbox), hbox, FALSE, TRUE, 0);
416 	       gtk_widget_show_all (iconbox);
417 	    }
418 	    /*
419 	     *  Config sections (except for Appearance) are
420 	     *  surrounded by a frame.
421 	     */
422 	    if (!strcaseeq (WMGetFromPLString (thispanel), "Appearance")
423 		&& !strcaseeq (WMGetFromPLString (thispanel), "Paths"))
424 	    {
425 	       GtkWidget *frame;
426 
427 	       frame = gtk_frame_new (section ? D_(WMGetFromPLString (info)) : NULL);
428 	       gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
429 	       gtk_frame_set_shadow_type (GTK_FRAME (frame),
430 					  GTK_SHADOW_ETCHED_IN);
431 	       gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
432 	       gtk_container_add (GTK_CONTAINER (frame), box);
433 
434 	       gtk_container_add (GTK_CONTAINER (page), frame);
435 	    }
436 	    else
437 	       gtk_container_add (GTK_CONTAINER (page), box);
438 
439 	    gtk_widget_show_all (page);
440 
441 	    while (gtk_events_pending())		/* FreeBSD workaround */
442 	       gtk_main_iteration();
443 
444 	    /*
445 	     *  Generate special containers for Menu, Themes and Appearance
446 	     */
447 	    if (strcaseeq (WMGetFromPLString (thispanel), "Menu") &&
448 		(!section || strcaseeq (section, "Menu")))
449 	       box = rootmenu_dialog (box, tooltips);
450 	    if (strcaseeq (WMGetFromPLString (thispanel), "Themes") &&
451 		(!section || strcaseeq (section, "Themes")))
452 	       box = theme_browser (box, section != NULL);
453 	    if (strcaseeq (WMGetFromPLString (thispanel), "Appearance") &&
454 		(!section || strcaseeq (section, "Appearance")))
455 	       appearance_container (type, thispanel, &options, box);
456 
457 	    /*
458 	     *  Store container widget of current panel
459 	     */
460 	    {
461 	       proplist_t data;
462 	       data = WMCreatePLDataWithBytes ((unsigned char *) &box, sizeof (GtkWidget *));
463 	       WMPutInPLDictionary (entry, plwidget, data);
464 	       WMReleasePropList (data);
465 	    }
466 	 }
467       }
468       WMReleasePropList (tab);
469    }
470 
471    if (!section_found)
472       error (_("No sections to show!"));
473 
474    while (gtk_events_pending())		/* FreeBSD workaround */
475       gtk_main_iteration();
476 
477    /*
478     *  Add config widget for each defined Window Maker attribute
479     */
480    {
481       proplist_t all_keys = WMGetPLDictionaryKeys (wmconfig);
482       unsigned   melem     = WMGetPropListItemCount (all_keys);
483       unsigned	 n;
484 
485       for (n = 0; n < melem; n++)
486       {
487 	 proplist_t key    = WMGetFromPLArray (all_keys, n);
488 	 proplist_t value  = WMGetFromPLDictionary (windowmaker, key);
489 	 proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
490 	 proplist_t group  = WMGetFromPLDictionary (keydef, plgrp);
491 	 proplist_t title  = WMGetFromPLDictionary (keydef, pltitle);
492 	 proplist_t range;
493 	 proplist_t info;
494 	 proplist_t rinfo;
495 	 GtkWidget  *page_box;
496 	 char	    *name;
497 	 char	    *type;
498 	 proplist_t ptype;
499 	 proplist_t pentry;
500 
501 	 if (strcaseeq (WMGetFromPLString (group), "None"))
502 	    continue;
503 
504 #ifndef FREEBSD_SYSTEM
505 	 /*
506 	  *  Update of progress bar window
507 	  */
508 	 if (!section)
509 	 {
510 	    gtk_label_set_text (GTK_LABEL (progress_label), WMGetFromPLString (key));
511 	    gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_bar),
512 				     n / (double) melem);
513 	    gtk_widget_draw (progress_window, NULL);
514 	 }
515 #endif /* not FREEBSD_SYSTEM */
516 
517 	 while (gtk_events_pending())
518 	    gtk_main_iteration();
519 
520 	 range = WMGetFromPLDictionary (keydef, plrange);
521 	 rinfo = WMGetFromPLDictionary (keydef, plrinfo);
522 	 info  = WMGetFromPLDictionary (keydef, plinfo);
523 	 name  = WMGetFromPLString (key);
524 	 type  = WMGetFromPLString (WMGetFromPLDictionary (keydef, pltype));
525 
526 	 /*
527 	  *  We need attributes of actived sections only
528 	  */
529 	 {
530 	    char        *thissecname = WMGetFromPLString (group);
531 	    const node*  cur;
532 	    bool_t 	 matches;
533 
534 	    for(cur = sections, matches = NO; cur && !matches; cur = cur->next)
535 	       if (strncaseeq(thissecname,cur->name,cur->length))
536 		  matches = YES;
537 
538 	    if (sections &&
539 		((matches && sections_restriction_type==NO)
540 		 || (!matches && sections_restriction_type==YES)))
541 	       continue;
542 	    /* we are here since this section is allowed */
543 	    section_found = TRUE;
544 	 }
545 
546 	 /*
547 	  *  Get main group and corresponding container
548 	  */
549 	 {
550 	    char	*pos;
551 	    proplist_t	pgroup;
552 	    proplist_t  pbox;
553 	    char	*groupname = g_strdup (WMGetFromPLString (group));
554 
555 	    if ((pos = strchr (groupname, '/')))
556 	       *pos = 0;
557 
558 	    pgroup = WMCreatePLString (groupname);
559 	    pentry = WMGetFromPLDictionary (panel, pgroup);
560 	    pbox   = WMGetFromPLDictionary (pentry, plwidget);
561 	    ptype  = WMGetFromPLDictionary (pentry, pltype);
562 	    WMReleasePropList (pgroup);
563 
564 	    if (!pentry || !pbox || !ptype)
565 	       continue;
566 
567 	    if (WMIsPLDictionary (ptype)) /* get sub entry */
568 	    {
569 	       char *subname = pos + 1;
570 
571 	       if ((pos = strchr (subname, '/')))
572 		  *pos = 0;
573 
574 	       pgroup = WMCreatePLString (subname);
575 	       pentry = WMGetFromPLDictionary (ptype, pgroup);
576 	       ptype  = WMGetFromPLDictionary (pentry, pltype);
577 	       WMReleasePropList (pgroup);
578 
579 	       if (WMIsPLDictionary (ptype) && pos) /* get sub sub entry */
580 	       {
581 		  pgroup = WMCreatePLString (pos + 1);
582 		  pentry = WMGetFromPLDictionary (ptype, pgroup);
583 		  WMReleasePropList (pgroup);
584 		  if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor") )
585 		     pbox = WMGetFromPLDictionary (pentry, plcolor);
586 		  else if (strcaseeq (type, "Font"))
587 		     pbox = WMGetFromPLDictionary (pentry, plfont);
588 		  else if (strcaseeq (type, "Texture"))
589 		     pbox = WMGetFromPLDictionary (pentry, pltexture);
590 		  else
591 		     pbox = WMGetFromPLDictionary (pentry, plwidget);
592 	       }
593 	       else
594 	       {
595 		  if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor"))
596 		     pbox = WMGetFromPLDictionary (pentry, plcolor);
597 		  else if (strcaseeq (type, "Font"))
598 		     pbox = WMGetFromPLDictionary (pentry, plfont);
599 		  else if (strcaseeq (type, "Texture"))
600 		     pbox = WMGetFromPLDictionary (pentry, pltexture);
601 		  else
602 		     pbox = WMGetFromPLDictionary (pentry, plwidget);
603 	       }
604 	       page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);
605 	       {
606 		  GtkWidget *frame;
607 		  frame = gtk_object_get_user_data (GTK_OBJECT (page_box));
608 
609 		  if (frame && GTK_IS_WIDGET (frame)
610 		      && !GTK_WIDGET_VISIBLE (frame))
611 		     gtk_widget_show_all (frame);
612 	       }
613 	    }
614 	    else
615 	       page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);
616 
617 	    Free (groupname);
618 	 }
619 
620 	 while (gtk_events_pending())
621 	    gtk_main_iteration();
622 
623 	 /*
624 	  *  Use different dialogs for different attribute types
625 	  */
626 	 if (strcaseeq ("Bool", type))
627 	 {
628 	    boolean_dialog (page_box, key, value, title);
629 	 }
630 	 else if (strcaseeq ("IBool", type))
631 	 {
632 	    iboolean_dialog (page_box, key, value, title);
633 	 }
634 	 else if (strcaseeq ("String", type)
635 		  && !strcaseeq ("ModifierKey", WMGetFromPLString (key)))
636 	 {
637 	    string_dialog (page_box, key, value, range, rinfo, title);
638 	 }
639 	 else if (strcaseeq ("Int", type))
640 	 {
641 	    int_dialog (page_box, key, value, range, rinfo, title);
642 	 }
643 	 else if (strcaseeq ("Text", type))
644 	 {
645 	    text_dialog (page_box, key, value, title);
646 	 }
647 	 else if (strcaseeq ("Font", type) || strcaseeq ("Color", type)
648 		  || strcaseeq ("TextColor", type)
649 		  || strcaseeq ("Texture", type))
650 	 {
651 	    GtkWidget	*widget;
652 	    proplist_t	data;
653 
654 	    if (strcaseeq ("Font", type))
655 	       widget = font_dialog (page_box, key, value, info);
656 	    else if (strcaseeq ("Texture", type))
657 	    {
658 	       GtkWidget  *box     = NULL;
659 	       proplist_t fontbox = WMGetFromPLDictionary (pentry, plfont);
660 
661 	       if (fontbox)
662 		  box = * (GtkWidget **) WMGetPLDataBytes (fontbox);
663 	       widget = texture_dialog (page_box, box, key);
664 	    }
665 #ifdef HAVE_LIBWMFUN
666 	    else if (strcaseeq ("TextColor", type))
667 	       widget = extended_color_dialog (page_box, key, value, tooltips,
668 					       info, title);
669 #endif /* HAVE_LIBWMFUN */
670 	    else
671 	       widget = color_dialog (page_box, key, value, tooltips,
672 				      info, title);
673 
674 	    data = WMCreatePLDataWithBytes ((unsigned char *) &widget, sizeof (GtkWidget *));
675 	    WMPutInPLDictionary (keydef, plwidget, data);
676 	    WMReleasePropList (data);
677 
678 	    if (WMIsPLDictionary (ptype)) /* subsubbox */
679 	       gtk_widget_hide (widget);
680 	 }
681 	 else if (strcaseeq ("Key", type))
682 	 {
683 	    add_shortcut (page_box, key);
684 	 }
685 	 else if (strcaseeq ("Pathlist", type))
686 	 {
687 	    if (!streq (WMGetFromPLString (key), "ThemePath"))
688 	       path_dialog (page_box, key, value, tooltips, info);
689 	 }
690       }
691       WMReleasePropList (all_keys);
692    }
693 
694    gtk_widget_set_usize (main_window,
695 			 min (gdk_screen_width () - 64,
696 			      790 - (section ? 150 : 0)),
697 			 min (gdk_screen_height () - 64, 600));
698 
699    while (gtk_events_pending())
700       gtk_main_iteration();
701 
702    toggle_save (changed = NO, NULL);
703 #ifndef FREEBSD_SYSTEM
704    if (!section)
705       gtk_widget_destroy (progress_window);
706 #endif /* not FREEBSD_SYSTEM */
707 
708    WMReleasePropList (plinfo);
709    WMReleasePropList (pltype);
710    WMReleasePropList (plicon);
711    WMReleasePropList (plwidget);
712    WMReleasePropList (plcolor);
713    WMReleasePropList (plfont);
714    WMReleasePropList (pltexture);
715    WMReleasePropList (plrange);
716    WMReleasePropList (plgrp);
717    WMReleasePropList (pltitle);
718 
719    g_list_foreach (options, init_option_menu, NULL);
720    g_list_free (options);
721 
722    while (gtk_events_pending())
723       gtk_main_iteration();
724 
725    check_widgetstyle ();
726 #ifdef GETSTYLE
727    get_theme_attributes ();
728 #endif /* GETSTYLE */
729 
730    while (gtk_events_pending())
731       gtk_main_iteration();
732 
733    gtk_widget_show (main_window);
734 
735    {
736       char *path = g_strconcat (g_get_home_dir (), "/.wmakerconf", NULL);
737       DIR  *dir;
738 
739       if (!(dir = opendir (path)))
740       {
741 	 dialog_popup (DIALOG_INFO, generate_previews, NULL,
742 		       _("Directory $HOME/.wmakerconf does not exist yet.\n"
743 			 "This directory is used to store the previews of all "
744 			 "images.\nShould I generate this directory and the "
745 			 "image previews now?"));
746       }
747       else
748 	 closedir (dir);
749    }
750 
751    gtk_main ();
752    gtk_widget_destroy (main_window);
753    cleanup_textures ();
754 #ifdef GETSTYLE
755    cleanup_themes ();
756 #endif /* GETSTYLE */
757 }
758 
759 void
check_widgetstyle(void)760 check_widgetstyle (void)
761 {
762    proplist_t plnewstyle = WMCreatePLString ("NewStyle");
763    proplist_t value	  = WMGetFromPLDictionary (windowmaker, plnewstyle);
764 
765    if (widgetstyle_item)
766       gtk_widget_set_sensitive (widgetstyle_item, !convert_bool (value));
767 
768    WMReleasePropList (plnewstyle);
769 }
770 
771 char *
get_pixmap_path(const char * name)772 get_pixmap_path (const char *name)
773 /*
774  *  Guess filename of pixmap 'name'.
775  *  Cycle through list of available paths or use absolute path
776  *  if name [0] == '/' or '~'.
777  *
778  *  Return value:
779  *	string with pixmap path on success
780  *	NULL if pixmap not found
781  */
782 {
783    if (name [0] == '/' || name [0] == '~') /* absolute path ? */
784    {
785       FILE *file;
786       char *path = expand_tilde (name);
787 
788       file = fopen (path, "r");
789       if (!file)
790       {
791 	 Free (path);
792 	 return NULL;
793       }
794       else
795       {
796 	 fclose (file);
797 	 return path;
798       }
799    }
800    else
801    {
802       unsigned	 n;
803       char	 *found	      = NULL;
804       proplist_t plpath      = WMCreatePLString ("PixmapPath");
805       proplist_t pixmap_path = WMGetFromPLDictionary (windowmaker, plpath);
806 
807       WMReleasePropList (plpath);
808 
809       for (n = 0; n < WMGetPropListItemCount (pixmap_path) && !found; n++)
810       {
811 	 FILE *file;
812 	 char *path = expand_tilde (WMGetFromPLString (WMGetFromPLArray (pixmap_path,
813 								    n)));
814 	 char *filename = g_strconcat (path, "/", name, NULL);
815 
816 	 Free (path);
817 	 file = fopen (filename, "r");
818 	 if (file)
819 	 {
820 	    found = filename;
821 	    fclose (file);
822 	 }
823 	 else
824 	    Free (filename);
825       }
826       return found;
827    }
828 }
829 
830 GtkWidget *
make_pixmap(const char * name,int width,int height,GtkWidget * pw)831 make_pixmap (const char *name, int width, int height, GtkWidget *pw)
832 /*
833  *  Genearate a new pixmap widget with pixmap 'name' of maximum size
834  *  'max_width' x 'max_height'. If 'pw' is already valid (i.e., != NULL)
835  *  just replace the pixmap of the widget.
836  *
837  *  Return value:
838  *	new or changed pixmap widget
839  */
840 {
841    char *path = get_pixmap_path (name);
842 
843    if (!path)
844    {
845       dialog_popup (DIALOG_ERROR, NULL, NULL,
846 		    _("Can't find pixmap\n'%s`\nin PixmapPath. Please update\n"
847 		      "your PixmapPath attribute."), name);
848       return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
849    }
850 
851 #if defined(PREVIEWS) && !defined(CONVERT)
852 
853    if (!pw && width > 0 && height > 0)
854       pw = make_image (PKGDATADIR "/black.xpm", width, height, pw);
855    pw = make_image (path, width, height, pw);
856 
857 #else  /* not PREVIEWS or CONVERT */
858 
859 #ifdef HAVE_STAT
860    /*
861     *  Don't load large XPM (may cause trouble with imlib)
862     */
863    {
864       struct stat buffer;
865 
866       if (strstr (path, ".xpm") && stat (path, &buffer) == 0
867 	  && buffer.st_size > 65000) /* image too large */
868       {
869 	 Free (path);
870 	 return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
871       }
872    }
873 #endif /* HAVE_STAT */
874 
875    {
876       GdkBitmap *mask   = NULL;
877       GdkPixmap *pixmap = NULL;
878 
879 #ifdef HAVE_IMLIB
880       if (use_imlib)
881       {
882 	 GdkImlibImage *image;
883 
884 	 image = gdk_imlib_load_image (path);
885 	 if (image)
886 	 {
887 	    if (width <= 0)
888 	       width = image->rgb_width;
889 	    if (height <= 0)
890 	       height = image->rgb_height;
891 	    if (image->rgb_width > width || image->rgb_height > height)
892 	    {
893 	       if (height * image->rgb_width > width * image->rgb_height)
894 		  height = width * image->rgb_height / image->rgb_width;
895 	       else
896 		  width  = height * image->rgb_width / image->rgb_height;
897 	    }
898 	    gdk_imlib_render (image, max (width, 22), max (height, 22));
899 	    pixmap = gdk_imlib_move_image (image);
900 	    mask   = gdk_imlib_move_mask (image);
901 	    if (strchr (g_path_get_basename (path), '.')) /* don't cache x-of-day */
902 	       gdk_imlib_destroy_image (image);
903 	    else
904 	       gdk_imlib_kill_image (image);
905 	 }
906       }
907       else
908 #else  /* not HAVE_IMLIB */
909 	 pixmap
910 	    = gdk_pixmap_create_from_xpm (main_window->window, &mask,
911 					  background, PKGDATADIR "/black.xpm");
912 #endif /* not HAVE_IMLIB */
913       if (!pixmap)			/* pixmap not found or unknown format */
914       {
915 	 static bool_t error_message = NO;
916 
917 	 if (!error_message)
918 	 {
919 	    dialog_popup (DIALOG_ERROR, NULL, NULL,
920 			  _("Unable to display pixmap\n'%s`\n"
921 			    "(format not supported).\n"
922 			    "See stderr for subsequent messages."), path);
923 	    error_message = YES;
924 	 }
925 	 else
926 	    warning (_("Can't display pixmap '%s`."), path);
927 	 Free (path);
928 	 return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
929       }
930       Free (path);
931       if (pw)
932 	 gtk_pixmap_set (GTK_PIXMAP (pw), pixmap, mask);
933       else
934       {
935 	 pw = gtk_pixmap_new (pixmap, mask);
936 	 gtk_widget_show (pw);
937       }
938    }
939 #endif /* not PREVIEWS or CONVERT */
940 
941    return pw;
942 }
943 
944 gint
quit(GtkWidget * widget,gpointer ptr)945 quit (GtkWidget *widget, gpointer ptr)
946 /*
947  *  Return from gtk_main () loop, i.e. leave the application.
948  *  Before quitting ask for confirmation.
949  *
950  *  No return value.
951  */
952 {
953    if (changed || rootmenu_changed ())
954    {
955       quit_and_save_popup (_("Some values are modified.\n"
956 			     "Do you want to save them before quitting?"),
957 			   save_config_file, (gpointer) "quit");
958       return TRUE;
959    }
960    else
961    {
962       gtk_main_quit ();
963       return TRUE;				/* do not delete window */
964    }
965 }
966 
967 static void
quit_and_save_popup(char * question,void (* save_function)(GtkWidget *,gpointer),gpointer dataptr)968 quit_and_save_popup (char *question,
969 		     void (*save_function) (GtkWidget *, gpointer),
970 		     gpointer dataptr)
971 /*
972  *  Popup dialog to ensure that current process is not killed until
973  *  user confirmation.
974  *  'question' is the text to be displayed.
975  *  'save_function' is called in case user confirms saving.
976  *  'dataptr' argument is passed to 'save_function'.
977  *
978  *  No return value.
979  */
980 {
981    GtkWidget *hbox;
982    GtkWidget *window, *button;
983 
984    window = gtk_dialog_new ();
985    gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
986    gtk_window_set_title (GTK_WINDOW (window), _("Save before quitting?"));
987    gtk_widget_realize (window);
988 
989    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
990 		       GTK_SIGNAL_FUNC (gtk_false), NULL);
991    gtk_signal_connect_object (GTK_OBJECT (window), "destroy",
992 			      GTK_SIGNAL_FUNC (gtk_widget_destroy),
993 			      GTK_OBJECT (window));
994 
995    hbox = gtk_hbox_new (FALSE, 5);
996    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox,
997 		       FALSE, FALSE, 0);
998    gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
999 
1000    gtk_box_pack_start (GTK_BOX (hbox),
1001 		       gtk_pixmap_new (p_array [P_INFO].pixmap,
1002 				       p_array [P_INFO].mask),
1003 		       TRUE, FALSE, 5);
1004 
1005    gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (question), TRUE, TRUE, 5);
1006 
1007    button = gtk_button_new_with_label (_("Yes"));
1008    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
1009 		       TRUE, TRUE, 10);
1010    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1011    gtk_widget_grab_default (button);
1012    gtk_signal_connect (GTK_OBJECT (button), "clicked",
1013 		       GTK_SIGNAL_FUNC (save_function), dataptr);
1014    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1015 			      (GtkSignalFunc) gtk_widget_destroy,
1016 			      GTK_OBJECT (window));
1017 
1018    button = gtk_button_new_with_label (_("No"));
1019    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
1020 		       TRUE, TRUE, 10);
1021    gtk_signal_connect (GTK_OBJECT (button), "clicked",
1022 		       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
1023 
1024    button = gtk_button_new_with_label (_("Cancel"));
1025    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
1026 		       TRUE, TRUE, 10);
1027    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1028 			      (GtkSignalFunc) gtk_widget_destroy,
1029 			      GTK_OBJECT (window));
1030 
1031    gtk_widget_show_all (window);
1032 }
1033 
1034 void
save_config_file(GtkWidget * widget,gpointer ptr)1035 save_config_file (GtkWidget *widget, gpointer ptr)
1036 /*
1037  *  Save 'WindowMaker' file if attributes have been changed.
1038  *
1039  *  No return value.
1040  *
1041  *  Side effects:
1042  *	'changed' is set to FALSE
1043  */
1044 {
1045    if (!save_rootmenu ())
1046       return;
1047 
1048    if (changed)
1049    {
1050       proplist_t newwm = WMCreatePLDictionary (NULL, NULL, NULL);
1051 
1052       /*
1053        *  Compare user attributes with system attributes
1054        */
1055       {
1056 	 proplist_t all_keys = WMGetPLDictionaryKeys (windowmaker) ;
1057 	 unsigned	 n;
1058 
1059 	 for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
1060 	 {
1061 	    proplist_t user;
1062 	    proplist_t key = WMGetFromPLArray (all_keys, n);
1063 
1064 	    user = WMGetFromPLDictionary (windowmaker, key);
1065 
1066 	    if (WMGetFromPLDictionary (plist_changed, key))
1067 	       WMPutInPLDictionary (newwm, key, WMDeepCopyPropList (user));
1068 	 }
1069 	 WMReleasePropList (all_keys);
1070       }
1071 
1072       if (WMWritePropListToFile (newwm, orig_wmaker_fname))
1073       {
1074 	 changed = NO;
1075 	 message (_("Window Maker config file '%s' saved."),
1076 		  orig_wmaker_fname);
1077       }
1078       else
1079       {
1080 	 dialog_popup (DIALOG_ERROR, NULL, NULL,
1081 		       _("Can't write to Window Maker file\n`%s'."),
1082 		       orig_wmaker_fname);
1083 	 return;
1084       }
1085       WMReleasePropList (newwm);
1086    }
1087 
1088    enable_revert ();
1089    toggle_save (FALSE, NULL);
1090 
1091    if (ptr && streq (ptr, "quit"))
1092       gtk_main_quit ();
1093 }
1094 
1095 /*****************************************************************************
1096 
1097 			       private code
1098 
1099 *****************************************************************************/
1100 
1101 static int
compare_fn(const void * p1,const void * p2)1102 compare_fn (const void *p1, const void *p2)
1103 { return strcmp(((names_t *)p1)->intlname, ((names_t *)p2)->intlname); }
1104 
1105 static void
appearance_container(proplist_t type,proplist_t thispanel,GList ** options,GtkWidget * box)1106 appearance_container (proplist_t type, proplist_t thispanel,
1107 		      GList **options, GtkWidget *box)
1108 /*
1109  *  Gererate sub-containers for each appearance sub-panel.
1110  */
1111 {
1112    proplist_t  subentries = WMGetPLDictionaryKeys (type);
1113    GtkWidget  *subbook    = gtk_notebook_new ();
1114    proplist_t  plinfo     = WMCreatePLString ("Info");
1115    proplist_t  plfont     = WMCreatePLString ("Fontbox");
1116    proplist_t  pltexture  = WMCreatePLString ("Texturebox");
1117    proplist_t  plcolor    = WMCreatePLString ("Colorbox");
1118    proplist_t  plwidget   = WMCreatePLString ("Widget");
1119    proplist_t  pltype     = WMCreatePLString ("Type");
1120    proplist_t  plicon     = WMCreatePLString ("Icon");
1121    unsigned    i;
1122 
1123    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (subbook), TRUE);
1124    gtk_notebook_set_scrollable (GTK_NOTEBOOK (subbook), TRUE);
1125    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (subbook), GTK_POS_TOP);
1126    gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (subbook), TRUE);
1127    gtk_box_pack_start (GTK_BOX (box), subbook, TRUE, TRUE, 0);
1128    gtk_container_set_border_width (GTK_CONTAINER (subbook), 10);
1129    gtk_widget_show_all (subbook);
1130 
1131    while (gtk_events_pending())
1132       gtk_main_iteration();
1133 
1134    for (i = 0; i < WMGetPropListItemCount (subentries); i++)
1135    {
1136       GtkWidget  *subpage;
1137       proplist_t  thissub  = WMGetFromPLArray (subentries, i);
1138       proplist_t  subentry = WMGetFromPLDictionary (type, thissub);
1139       proplist_t  subinfo  = WMGetFromPLDictionary (subentry, plinfo);
1140       proplist_t  subicon  = WMGetFromPLDictionary (subentry, plicon);
1141       proplist_t  subtype  = WMGetFromPLDictionary (subentry, pltype);
1142       char 	 *path     = NULL;
1143 
1144       if (subicon && WMIsPLString (subicon)) /* subsubsections ? */
1145 	 path = g_strconcat (PKGDATADIR, "/",
1146 			     WMGetFromPLString (subicon), NULL);
1147       subpage = create_page (GTK_NOTEBOOK (subbook),
1148 			     D_(WMGetFromPLString (subinfo)), path, FALSE);
1149       if (path)
1150 	 Free (path);
1151 
1152       {
1153 	 proplist_t data;
1154 
1155 	 data = WMCreatePLDataWithBytes ((unsigned char *) &subpage,
1156 			    sizeof (GtkWidget *));
1157 	 WMPutInPLDictionary (subentry, plwidget, data);
1158 	 WMReleasePropList (data);
1159       }
1160 
1161 
1162       while (gtk_events_pending())
1163 	 gtk_main_iteration();
1164 
1165       /*
1166        *  Add subboxes for color, texture and font
1167        */
1168       {
1169 	 GtkWidget  *vbox          = gtk_vbox_new (FALSE, 0);
1170 	 GtkWidget  *nw_hbox       = gtk_hbox_new (FALSE, 0);
1171 	 GtkWidget  *color_frame   = gtk_hbox_new (FALSE, 0);
1172 	 GtkWidget  *texture_frame = gtk_hbox_new (FALSE, 0);
1173 	 GtkWidget  *color_box     = gtk_hbox_new (FALSE, 0);
1174 	 GtkWidget  *texture_box   = gtk_vbox_new (FALSE, 0);
1175 	 GtkWidget  *hbox;
1176 	 proplist_t color_data;
1177 	 proplist_t texture_data;
1178 	 proplist_t font_data;
1179 
1180 	 gtk_container_add (GTK_CONTAINER (subpage), vbox);
1181 
1182 	 /*
1183 	  *  Overall boxes
1184 	  */
1185 	 gtk_box_pack_start (GTK_BOX (vbox), nw_hbox,
1186 			     FALSE, TRUE, 5);
1187 	 hbox = gtk_hbox_new (FALSE, 0);
1188 	 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
1189 	 gtk_box_pack_start (GTK_BOX (hbox), color_frame,
1190 			     TRUE, TRUE, 5);
1191 	 hbox = gtk_hbox_new (FALSE, 0);
1192 	 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
1193 	 gtk_box_pack_start (GTK_BOX (hbox), texture_frame,
1194 			     TRUE, TRUE, 5);
1195 	 while (gtk_events_pending())
1196 	    gtk_main_iteration();
1197 
1198 	 /*
1199 	  *  Color box
1200 	  */
1201 	 {
1202 	    GtkWidget  *frame = gtk_frame_new (_("Colors"));
1203 	    GtkWidget  *box   = color_box;
1204 
1205 	    gtk_box_pack_start (GTK_BOX (color_frame), frame,
1206 				TRUE, TRUE, 0);
1207 	    gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
1208 	    gtk_container_add (GTK_CONTAINER (frame), box);
1209 	    gtk_container_set_border_width (GTK_CONTAINER (box), 5);
1210 	    color_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
1211 				     sizeof (GtkWidget *));
1212 	    gtk_object_set_user_data (GTK_OBJECT (box),
1213 				      color_frame);
1214 	 }
1215 	 while (gtk_events_pending())
1216 	    gtk_main_iteration();
1217 	 /*
1218 	  *  Texture box
1219 	  */
1220 	 {
1221 	    GtkWidget  *frame = gtk_frame_new (_("Texture"));
1222 	    GtkWidget  *box   = texture_box;
1223 
1224 	    gtk_box_pack_start (GTK_BOX (texture_frame), frame,
1225 				TRUE, TRUE, 0);
1226 	    gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
1227 	    gtk_container_add (GTK_CONTAINER (frame), box);
1228 	    texture_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
1229 				       sizeof (GtkWidget *));
1230 	    gtk_object_set_user_data (GTK_OBJECT (box),
1231 				      texture_frame);
1232 	 }
1233 	 /*
1234 	  *  Font box
1235 	  */
1236 	 {
1237 	    font_data = WMCreatePLDataWithBytes ((unsigned char *) &nw_hbox,
1238 				    sizeof (GtkWidget *));
1239 	 }
1240 	 gtk_widget_show_all (subpage);
1241 	 gtk_widget_hide (color_frame);
1242 	 gtk_widget_hide (texture_frame);
1243 
1244 	 while (gtk_events_pending())
1245 	    gtk_main_iteration();
1246 
1247 	 /*
1248 	  *  Make option box with subsubsections and subboxes
1249 	  *  for color, texture and font
1250 	  */
1251 	 if (subtype && WMIsPLDictionary (subtype))
1252 	 {
1253 	    proplist_t ssentries = WMGetPLDictionaryKeys (subtype);
1254 	    unsigned   k;
1255 	    char	   *path;
1256 	    GtkWidget  *option_menu = gtk_option_menu_new ();
1257 	    GtkWidget  *menu        = gtk_menu_new ();
1258 
1259 	    path = g_strconcat (WMGetFromPLString (thispanel), "/",
1260 				WMGetFromPLString (thissub), NULL);
1261 
1262 	    for (k = 0; k < WMGetPropListItemCount (ssentries); k++)
1263 	    {
1264 	       proplist_t thisss;
1265 	       proplist_t ssentry;
1266 	       proplist_t ssinfo;
1267 	       GtkWidget  *menu_item;
1268 
1269 	       thisss    = WMGetFromPLArray (ssentries, k);
1270 	       ssentry   = WMGetFromPLDictionary (subtype, thisss);
1271 	       ssinfo    = WMGetFromPLDictionary (ssentry, plinfo);
1272 	       menu_item = gtk_menu_item_new_with_label (D_(WMGetFromPLString (ssinfo)));
1273 	       gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
1274 				   GTK_SIGNAL_FUNC (switch_subentries),
1275 				   path);
1276 	       gtk_object_set_user_data (GTK_OBJECT (menu_item),
1277 					 (gpointer) WMGetFromPLString (thisss));
1278 	       gtk_menu_append (GTK_MENU (menu), menu_item);
1279 	       gtk_widget_show (menu_item);
1280 
1281 	       WMPutInPLDictionary (ssentry, plcolor,
1282 					color_data);
1283 	       WMPutInPLDictionary (ssentry, pltexture,
1284 					texture_data);
1285 	       WMPutInPLDictionary (ssentry, plfont,
1286 					font_data);
1287 	       if (strcaseeq (WMGetFromPLString (thisss), "Widget"))
1288 		  widgetstyle_item = menu_item;
1289 	    }
1290 	    gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu),
1291 				      menu);
1292 	    gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), 0);
1293 	    gtk_widget_show (option_menu);
1294 	    *options = g_list_append (*options, option_menu);
1295 
1296 	    while (gtk_events_pending())
1297 	       gtk_main_iteration();
1298 
1299 	    {
1300 	       GtkWidget *frame;
1301 	       GtkWidget *box = gtk_hbox_new (TRUE, 0);
1302 
1303 	       frame = gtk_frame_new (D_(WMGetFromPLString (subinfo)));
1304 	       gtk_frame_set_label_align (GTK_FRAME (frame),
1305 					  0.5, 0.5);
1306 	       gtk_container_set_border_width (GTK_CONTAINER (box), 5);
1307 	       gtk_container_add (GTK_CONTAINER (frame), box);
1308 	       gtk_box_pack_start (GTK_BOX (box), option_menu,
1309 				   TRUE, TRUE, 0);
1310 	       gtk_box_pack_start (GTK_BOX (nw_hbox), frame,
1311 				   FALSE, TRUE, 5);
1312 	       gtk_widget_show_all (frame);
1313 	    }
1314 
1315 	    while (gtk_events_pending())
1316 	       gtk_main_iteration();
1317 
1318 	 }
1319 	 else
1320 	 {
1321 	    WMPutInPLDictionary (subentry, plcolor,
1322 				     color_data);
1323 	    WMPutInPLDictionary (subentry, pltexture,
1324 				     texture_data);
1325 	    WMPutInPLDictionary (subentry, plfont,
1326 				     font_data);
1327 	 }
1328 	 WMReleasePropList (color_data);
1329 	 WMReleasePropList (texture_data);
1330 	 WMReleasePropList (font_data);
1331       }
1332    }
1333    WMReleasePropList (subentries);
1334    WMReleasePropList (plinfo);
1335    WMReleasePropList (pltype);
1336    WMReleasePropList (plicon);
1337    WMReleasePropList (plwidget);
1338    WMReleasePropList (plcolor);
1339    WMReleasePropList (plfont);
1340    WMReleasePropList (pltexture);
1341 }
1342 
1343 static void
init_option_menu(gpointer data,gpointer user_data)1344 init_option_menu (gpointer data, gpointer user_data)
1345 {
1346    GtkOptionMenu *omenu = GTK_OPTION_MENU (data);
1347    GtkMenu	 *menu 	= GTK_MENU (gtk_option_menu_get_menu (omenu));
1348    GtkWidget	 *item 	= gtk_menu_get_active (menu);
1349 
1350    if (item)
1351       gtk_menu_item_activate (GTK_MENU_ITEM (item));
1352 }
1353 
1354 static GtkWidget *
create_page(GtkNotebook * notebook,const char * name,const char * pixmap_name,bool_t horizontal)1355 create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
1356 	     bool_t horizontal)
1357 /*
1358  *  Create a new group notebook page and append it to the given 'notebook'.
1359  *  'name' is the notebook label and 'pm' is the pixmap identifier.
1360  *
1361  *  Return value:
1362  *	container of label and pixmap
1363  */
1364 {
1365    GtkWidget *vbox 	= gtk_vbox_new (FALSE, 5);
1366    GtkWidget *label_box = NULL;
1367    GtkWidget *scrolled 	= NULL;
1368 
1369    if (name || pixmap_name)
1370    {
1371       label_box = horizontal ? gtk_hbox_new (FALSE, 5) : gtk_vbox_new (FALSE, 0);
1372       gtk_container_set_border_width (GTK_CONTAINER (label_box),
1373 				      horizontal ? 0 : 5);
1374       if (pixmap_name)
1375       {
1376 	 GdkPixmap *pixmap;
1377 	 GdkBitmap *mask;
1378 
1379 	 pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
1380 					      background, pixmap_name);
1381 	 if (pixmap)
1382 	    gtk_box_pack_start (GTK_BOX (label_box),
1383 				gtk_pixmap_new (pixmap, mask), FALSE, TRUE, 0);
1384       }
1385       if (name)
1386 	 gtk_box_pack_start (GTK_BOX (label_box), gtk_label_new (name),
1387 			     TRUE, TRUE, 0);
1388       gtk_widget_show_all (label_box);
1389    }
1390 
1391    scrolled = gtk_scrolled_window_new (NULL, NULL);
1392    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1393 				   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1394    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
1395 					  vbox);
1396    gtk_notebook_append_page_menu (notebook, scrolled, label_box, NULL);
1397    gtk_widget_show_all (scrolled);
1398 
1399    return vbox;
1400 }
1401 
1402 static void
switch_subentries(GtkWidget * widget,gpointer ptr)1403 switch_subentries (GtkWidget *widget, gpointer ptr)
1404 /*
1405  *  Show only widgets of chosen subsubentry
1406  */
1407 {
1408    unsigned	n;
1409    proplist_t	 all_keys = WMGetPLDictionaryKeys (wmconfig);
1410    proplist_t	 plgrp    = WMCreatePLString ("Group");
1411    proplist_t	 plwidget = WMCreatePLString ("Widget");
1412    char         *text     = gtk_object_get_user_data (GTK_OBJECT (widget));
1413    char         *prefix   = (char *) ptr;
1414    char		*path	  = g_strconcat (prefix, "/", text, NULL);
1415 
1416    for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
1417    {
1418       proplist_t key    = WMGetFromPLArray (all_keys, n);
1419       proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
1420       proplist_t data   = WMGetFromPLDictionary (keydef, plwidget);
1421 
1422       if (data)
1423       {
1424 	 proplist_t group = WMGetFromPLDictionary (keydef, plgrp);
1425 	 GtkWidget  *widget = * (GtkWidget **) WMGetPLDataBytes (data);
1426 
1427 	 if (strcaseeq (path, WMGetFromPLString (group)))
1428 	    gtk_widget_show (widget);
1429 	 else
1430 	 {
1431 	    char *right = strrchr (path, '/');
1432 
1433 	    /*  g_strncasecmp: only in GTK+1.1.x */
1434 	    {
1435 	       char *str1 = g_strdup (path);
1436 	       char *str2 = g_strdup (WMGetFromPLString (group));
1437 
1438 	       str1 [right - path] = 0;
1439 	       str2 [right - path] = 0;
1440 
1441 	       if (g_strcasecmp (str1, str2) == 0)
1442 		  gtk_widget_hide (widget);
1443 	       Free (str1);
1444 	       Free (str2);
1445 	    }
1446 	 }
1447       }
1448    }
1449    WMReleasePropList (plwidget);
1450    WMReleasePropList (plgrp);
1451 }
1452 
1453