/*
* window.c: GTK stuff
*
* Written by: Ullrich Hafner
*
* Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*/
/*
* $Date: 2000/09/03 19:22:06 $
* $Author: hafner $
* $Revision: 1.123 $
* $State: Exp $
*/
#include "config.h"
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif /* not HAVE_STDLIB_H */
#if HAVE_STRING_H
# include <string.h>
#else /* not HAVE_STRING_H */
# include <strings.h>
#endif /* not HAVE_STRING_H */
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */
#include <stdio.h>
#include <gtk/gtk.h>
#include "proplist_t.h"
/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
# include <dirent.h>
# define NLENGTH(dirent) (strlen ((dirent)->d_name))
#else
# define dirent direct
# define NLENGTH(dirent) ((dirent)->d_namlen)
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYS_DIR_H */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif /* HAVE_NDIR_H */
#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
#ifdef HAVE_IMLIB
#include <gdk_imlib.h>
#endif /* HAVE_IMLIB */
#include "window.h"
#include "icons.h"
#include "misc.h"
#include "dialog.h"
#include "texture.h"
#include "keys.h"
#include "menu.h"
#include "shortcuts.h"
#include "rootmenu.h"
#include "simple.h"
#include "path.h"
#include "themebrowser.h"
#include "rimage.h"
#include "error.h"
/*****************************************************************************
global variables
*****************************************************************************/
bool_t changed = NO;
bool_t use_imlib = NO;
GtkWidget *main_window = NULL;
GdkColor *background = NULL;
GtkTooltips *tooltips = NULL;
proplist_t windowmaker = NULL;
proplist_t wmconfig = NULL;
extern char *orig_wmaker_fname;
extern proplist_t plist_changed;
extern proplist_t pl_yes;
GtkWidget *widgetstyle_item = NULL;
/*****************************************************************************
prototypes
*****************************************************************************/
void
update (gpointer ptr, proplist_t value);
static GtkWidget *
create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
bool_t horizontal);
static void
quit_and_save_popup (char *question,
void (*yes_function) (GtkWidget *, gpointer),
gpointer dataptr);
static void
switch_subentries (GtkWidget *widget, gpointer ptr);
static void
init_option_menu (gpointer data, gpointer user_data);
static void
appearance_container (proplist_t type, proplist_t thispanel,
GList **options, GtkWidget *box);
static int
compare_fn (const void * p1, const void * p2);
typedef struct { char * name; char * intlname; } names_t;
/*****************************************************************************
public code
*****************************************************************************/
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)
/*
* Create root window and call the event loop of GTK
*
* No return value.
*/
{
GtkWidget *box1;
GtkWidget *notebook;
#ifndef FREEBSD_SYSTEM
GtkWidget *progress_window = NULL;
GtkWidget *progress_label = NULL;
GtkWidget *progress_bar = NULL;
#endif /* not FREEBSD_SYSTEM */
GtkWidget *toolbar;
proplist_t plinfo = WMCreatePLString ("Info");
proplist_t pltype = WMCreatePLString ("Type");
proplist_t plicon = WMCreatePLString ("Icon");
proplist_t pltitle = WMCreatePLString ("Title");
proplist_t plwidget = WMCreatePLString ("Widget");
proplist_t plcolor = WMCreatePLString ("Colorbox");
proplist_t plfont = WMCreatePLString ("Fontbox");
proplist_t pltexture = WMCreatePLString ("Texturebox");
proplist_t plgrp = WMCreatePLString ("Group");
proplist_t plrange = WMCreatePLString ("Range");
proplist_t plrinfo = WMCreatePLString ("RangeInfo");
GList *options = NULL;
bool_t section_found = NO;
GtkWidget *iconbox = gtk_hbox_new (FALSE, 0);
char *section = NULL; /* will point to something if only
one section will be shown*/
#if defined(PREVIEWS) && !defined(CONVERT)
init_wraster_lib ();
#endif /* defined(PREVIEWS) && !defined(CONVERT) */
windowmaker = wmlist;
wmconfig = wmc;
if (sections_restriction_type == 1 && sections && !sections->next)
section = sections->name;
/*
* Progress bar window (only if not on FreeBSD and section is not given)
*/
#ifndef FREEBSD_SYSTEM
if (!section)
{
GtkWidget *vbox;
progress_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (progress_window),
PACKAGE " " VERSION " init ...");
gtk_container_set_border_width (GTK_CONTAINER (progress_window), 10);
gtk_signal_connect (GTK_OBJECT (progress_window), "delete_event",
GTK_SIGNAL_FUNC (gtk_true), NULL);
gtk_widget_set_usize (progress_window, 250, -1);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (progress_window), vbox);
progress_label = gtk_label_new ("");
gtk_box_pack_start (GTK_BOX (vbox), progress_label, FALSE, TRUE, 0);
{
GtkAdjustment *adj;
adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 300, 0, 0, 0);
progress_bar = gtk_progress_bar_new_with_adjustment (adj);
gtk_progress_set_format_string (GTK_PROGRESS (progress_bar), "[%p%%]");
gtk_progress_set_show_text (GTK_PROGRESS (progress_bar), YES);
}
gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 0);
gtk_widget_show_all (progress_window);
}
#endif /* not FREEBSD_SYSTEM */
/*
* Fallback if libwraster is not (correctly) installed
*/
#ifdef HAVE_IMLIB
{
GdkVisual *gdkvisual;
GdkColormap *gdkcmap;
gdk_imlib_init ();
gdkvisual = gdk_imlib_get_visual ();
gdkcmap = gdk_imlib_get_colormap ();
if (gdkvisual && gdkcmap)
{
gtk_widget_push_visual (gdkvisual);
gtk_widget_push_colormap (gdkcmap);
use_imlib = YES;
}
else
use_imlib = NO;
}
#endif /* HAVE_IMLIB */
gtk_widget_push_visual (gdk_rgb_get_visual ());
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
/*
* Main window
*/
main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (main_window), "delete_event",
GTK_SIGNAL_FUNC (quit), NULL);
gtk_widget_realize (main_window);
background = &main_window->style->bg [GTK_STATE_NORMAL];
init_pixmaps ();
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
box1 = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (main_window), box1);
tooltips = gtk_tooltips_new ();
gtk_widget_show (box1);
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Menu and toolbox
*/
gtk_box_pack_start (GTK_BOX(box1),
make_menubar (logwindow, section == NULL, noinet),
FALSE, TRUE, 0);
if (section)
{
gtk_box_pack_start (GTK_BOX(box1), iconbox, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX(iconbox), toolbar = make_toolbar (noinet),
FALSE, TRUE, 0);
}
else
gtk_box_pack_start (GTK_BOX(box1), toolbar = make_toolbar (noinet),
FALSE, TRUE, 0);
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Notebook for all different wmakerconf sections
*/
notebook = gtk_notebook_new ();
gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (notebook), FALSE);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), TRUE);
gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
gtk_box_pack_start (GTK_BOX (box1), notebook, TRUE, TRUE, 0);
gtk_container_set_border_width (GTK_CONTAINER (notebook), section ? 5 : 10);
gtk_widget_show_all (notebook);
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Generate notebook page for every section.
* Section information is extracted from config file 'WMWmakerconf'.
*/
{
proplist_t tab_orig = WMGetPLDictionaryKeys (panel);
proplist_t tab = WMCreatePLArray (NULL);
names_t *tab_s;
unsigned n;
int size = WMGetPropListItemCount (tab_orig);
/* Sort the tabs alphabetically by the current translation.
* (OK, technically this isn't quite correct since the compare
* function is strcmp and the text ought to be UTF-8...)
* Unfortunately libWINGs provides no convenient way to do this. */
tab_s = malloc (size * sizeof (names_t));
for (n = 0; n < size; n++) {
proplist_t thispanel = WMGetFromPLArray (tab_orig, n);
proplist_t entry = WMGetFromPLDictionary (panel, thispanel);
proplist_t info = WMGetFromPLDictionary (entry, plinfo);
tab_s[n].name = WMGetFromPLString (thispanel);
tab_s[n].intlname = D_(WMGetFromPLString(info));
}
qsort (tab_s, size, sizeof (names_t), compare_fn);
for (n = 0; n < size; n++)
WMAddToPLArray (tab, WMCreatePLString (tab_s[n].name));
free (tab_s);
WMReleasePropList (tab_orig);
for (n = 0; n < size; n++)
{
proplist_t thispanel = WMGetFromPLArray (tab, n);
proplist_t entry = WMGetFromPLDictionary (panel, thispanel);
proplist_t info = WMGetFromPLDictionary (entry, plinfo);
proplist_t icon = WMGetFromPLDictionary (entry, plicon);
proplist_t type = WMGetFromPLDictionary (entry, pltype);
GtkWidget *page;
if (!icon || !info || !WMIsPLString (info) || !WMIsPLString (icon))
error (_("'%s': parse error."), conffile);
/*
* Check whether the current section is allowed
*/
{
char *thissecname = WMGetFromPLString (thispanel);
const node *cur;
bool_t matches;
for (cur = sections, matches = NO; cur && !matches; cur = cur->next)
if (strcaseeq (thissecname, cur->name))
matches = YES;
if (sections &&
((matches && sections_restriction_type==NO)
|| (!matches && sections_restriction_type==YES)))
continue;
/* we are here since this section is allowed */
section_found = TRUE;
}
/*
* Create new notbook page (use icon given in WMWmakerconf)
*/
{
char *path = g_strconcat (PKGDATADIR, "/", WMGetFromPLString (icon), NULL);
page = create_page (GTK_NOTEBOOK (notebook), D_(WMGetFromPLString (info)),
path, TRUE);
Free (path);
}
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Create container for config widgets
*/
{
GtkWidget *box = gtk_vbox_new (FALSE, 5);
gtk_widget_show (box);
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Use different layout if section is given:
* Notebook border and tabs are invisible, section icon is
* shown in the top right corner.
*/
if (section)
{
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkWidget *image;
GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
char *path = g_strconcat (PKGDATADIR, "/",
WMGetFromPLString (icon), NULL);
pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
background, path);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
image = gtk_pixmap_new (pixmap, mask);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
gtk_box_pack_end (GTK_BOX(iconbox), hbox, FALSE, TRUE, 0);
gtk_widget_show_all (iconbox);
}
/*
* Config sections (except for Appearance) are
* surrounded by a frame.
*/
if (!strcaseeq (WMGetFromPLString (thispanel), "Appearance")
&& !strcaseeq (WMGetFromPLString (thispanel), "Paths"))
{
GtkWidget *frame;
frame = gtk_frame_new (section ? D_(WMGetFromPLString (info)) : NULL);
gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
gtk_frame_set_shadow_type (GTK_FRAME (frame),
GTK_SHADOW_ETCHED_IN);
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
gtk_container_add (GTK_CONTAINER (frame), box);
gtk_container_add (GTK_CONTAINER (page), frame);
}
else
gtk_container_add (GTK_CONTAINER (page), box);
gtk_widget_show_all (page);
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Generate special containers for Menu, Themes and Appearance
*/
if (strcaseeq (WMGetFromPLString (thispanel), "Menu") &&
(!section || strcaseeq (section, "Menu")))
box = rootmenu_dialog (box, tooltips);
if (strcaseeq (WMGetFromPLString (thispanel), "Themes") &&
(!section || strcaseeq (section, "Themes")))
box = theme_browser (box, section != NULL);
if (strcaseeq (WMGetFromPLString (thispanel), "Appearance") &&
(!section || strcaseeq (section, "Appearance")))
appearance_container (type, thispanel, &options, box);
/*
* Store container widget of current panel
*/
{
proplist_t data;
data = WMCreatePLDataWithBytes ((unsigned char *) &box, sizeof (GtkWidget *));
WMPutInPLDictionary (entry, plwidget, data);
WMReleasePropList (data);
}
}
}
WMReleasePropList (tab);
}
if (!section_found)
error (_("No sections to show!"));
while (gtk_events_pending()) /* FreeBSD workaround */
gtk_main_iteration();
/*
* Add config widget for each defined Window Maker attribute
*/
{
proplist_t all_keys = WMGetPLDictionaryKeys (wmconfig);
unsigned melem = WMGetPropListItemCount (all_keys);
unsigned n;
for (n = 0; n < melem; n++)
{
proplist_t key = WMGetFromPLArray (all_keys, n);
proplist_t value = WMGetFromPLDictionary (windowmaker, key);
proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
proplist_t group = WMGetFromPLDictionary (keydef, plgrp);
proplist_t title = WMGetFromPLDictionary (keydef, pltitle);
proplist_t range;
proplist_t info;
proplist_t rinfo;
GtkWidget *page_box;
char *name;
char *type;
proplist_t ptype;
proplist_t pentry;
if (strcaseeq (WMGetFromPLString (group), "None"))
continue;
#ifndef FREEBSD_SYSTEM
/*
* Update of progress bar window
*/
if (!section)
{
gtk_label_set_text (GTK_LABEL (progress_label), WMGetFromPLString (key));
gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_bar),
n / (double) melem);
gtk_widget_draw (progress_window, NULL);
}
#endif /* not FREEBSD_SYSTEM */
while (gtk_events_pending())
gtk_main_iteration();
range = WMGetFromPLDictionary (keydef, plrange);
rinfo = WMGetFromPLDictionary (keydef, plrinfo);
info = WMGetFromPLDictionary (keydef, plinfo);
name = WMGetFromPLString (key);
type = WMGetFromPLString (WMGetFromPLDictionary (keydef, pltype));
/*
* We need attributes of actived sections only
*/
{
char *thissecname = WMGetFromPLString (group);
const node* cur;
bool_t matches;
for(cur = sections, matches = NO; cur && !matches; cur = cur->next)
if (strncaseeq(thissecname,cur->name,cur->length))
matches = YES;
if (sections &&
((matches && sections_restriction_type==NO)
|| (!matches && sections_restriction_type==YES)))
continue;
/* we are here since this section is allowed */
section_found = TRUE;
}
/*
* Get main group and corresponding container
*/
{
char *pos;
proplist_t pgroup;
proplist_t pbox;
char *groupname = g_strdup (WMGetFromPLString (group));
if ((pos = strchr (groupname, '/')))
*pos = 0;
pgroup = WMCreatePLString (groupname);
pentry = WMGetFromPLDictionary (panel, pgroup);
pbox = WMGetFromPLDictionary (pentry, plwidget);
ptype = WMGetFromPLDictionary (pentry, pltype);
WMReleasePropList (pgroup);
if (!pentry || !pbox || !ptype)
continue;
if (WMIsPLDictionary (ptype)) /* get sub entry */
{
char *subname = pos + 1;
if ((pos = strchr (subname, '/')))
*pos = 0;
pgroup = WMCreatePLString (subname);
pentry = WMGetFromPLDictionary (ptype, pgroup);
ptype = WMGetFromPLDictionary (pentry, pltype);
WMReleasePropList (pgroup);
if (WMIsPLDictionary (ptype) && pos) /* get sub sub entry */
{
pgroup = WMCreatePLString (pos + 1);
pentry = WMGetFromPLDictionary (ptype, pgroup);
WMReleasePropList (pgroup);
if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor") )
pbox = WMGetFromPLDictionary (pentry, plcolor);
else if (strcaseeq (type, "Font"))
pbox = WMGetFromPLDictionary (pentry, plfont);
else if (strcaseeq (type, "Texture"))
pbox = WMGetFromPLDictionary (pentry, pltexture);
else
pbox = WMGetFromPLDictionary (pentry, plwidget);
}
else
{
if (strcaseeq (type, "Color") || strcaseeq (type, "TextColor"))
pbox = WMGetFromPLDictionary (pentry, plcolor);
else if (strcaseeq (type, "Font"))
pbox = WMGetFromPLDictionary (pentry, plfont);
else if (strcaseeq (type, "Texture"))
pbox = WMGetFromPLDictionary (pentry, pltexture);
else
pbox = WMGetFromPLDictionary (pentry, plwidget);
}
page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);
{
GtkWidget *frame;
frame = gtk_object_get_user_data (GTK_OBJECT (page_box));
if (frame && GTK_IS_WIDGET (frame)
&& !GTK_WIDGET_VISIBLE (frame))
gtk_widget_show_all (frame);
}
}
else
page_box = * (GtkWidget **) WMGetPLDataBytes (pbox);
Free (groupname);
}
while (gtk_events_pending())
gtk_main_iteration();
/*
* Use different dialogs for different attribute types
*/
if (strcaseeq ("Bool", type))
{
boolean_dialog (page_box, key, value, title);
}
else if (strcaseeq ("IBool", type))
{
iboolean_dialog (page_box, key, value, title);
}
else if (strcaseeq ("String", type)
&& !strcaseeq ("ModifierKey", WMGetFromPLString (key)))
{
string_dialog (page_box, key, value, range, rinfo, title);
}
else if (strcaseeq ("Int", type))
{
int_dialog (page_box, key, value, range, rinfo, title);
}
else if (strcaseeq ("Text", type))
{
text_dialog (page_box, key, value, title);
}
else if (strcaseeq ("Font", type) || strcaseeq ("Color", type)
|| strcaseeq ("TextColor", type)
|| strcaseeq ("Texture", type))
{
GtkWidget *widget;
proplist_t data;
if (strcaseeq ("Font", type))
widget = font_dialog (page_box, key, value, info);
else if (strcaseeq ("Texture", type))
{
GtkWidget *box = NULL;
proplist_t fontbox = WMGetFromPLDictionary (pentry, plfont);
if (fontbox)
box = * (GtkWidget **) WMGetPLDataBytes (fontbox);
widget = texture_dialog (page_box, box, key);
}
#ifdef HAVE_LIBWMFUN
else if (strcaseeq ("TextColor", type))
widget = extended_color_dialog (page_box, key, value, tooltips,
info, title);
#endif /* HAVE_LIBWMFUN */
else
widget = color_dialog (page_box, key, value, tooltips,
info, title);
data = WMCreatePLDataWithBytes ((unsigned char *) &widget, sizeof (GtkWidget *));
WMPutInPLDictionary (keydef, plwidget, data);
WMReleasePropList (data);
if (WMIsPLDictionary (ptype)) /* subsubbox */
gtk_widget_hide (widget);
}
else if (strcaseeq ("Key", type))
{
add_shortcut (page_box, key);
}
else if (strcaseeq ("Pathlist", type))
{
if (!streq (WMGetFromPLString (key), "ThemePath"))
path_dialog (page_box, key, value, tooltips, info);
}
}
WMReleasePropList (all_keys);
}
gtk_widget_set_usize (main_window,
min (gdk_screen_width () - 64,
790 - (section ? 150 : 0)),
min (gdk_screen_height () - 64, 600));
while (gtk_events_pending())
gtk_main_iteration();
toggle_save (changed = NO, NULL);
#ifndef FREEBSD_SYSTEM
if (!section)
gtk_widget_destroy (progress_window);
#endif /* not FREEBSD_SYSTEM */
WMReleasePropList (plinfo);
WMReleasePropList (pltype);
WMReleasePropList (plicon);
WMReleasePropList (plwidget);
WMReleasePropList (plcolor);
WMReleasePropList (plfont);
WMReleasePropList (pltexture);
WMReleasePropList (plrange);
WMReleasePropList (plgrp);
WMReleasePropList (pltitle);
g_list_foreach (options, init_option_menu, NULL);
g_list_free (options);
while (gtk_events_pending())
gtk_main_iteration();
check_widgetstyle ();
#ifdef GETSTYLE
get_theme_attributes ();
#endif /* GETSTYLE */
while (gtk_events_pending())
gtk_main_iteration();
gtk_widget_show (main_window);
{
char *path = g_strconcat (g_get_home_dir (), "/.wmakerconf", NULL);
DIR *dir;
if (!(dir = opendir (path)))
{
dialog_popup (DIALOG_INFO, generate_previews, NULL,
_("Directory $HOME/.wmakerconf does not exist yet.\n"
"This directory is used to store the previews of all "
"images.\nShould I generate this directory and the "
"image previews now?"));
}
else
closedir (dir);
}
gtk_main ();
gtk_widget_destroy (main_window);
cleanup_textures ();
#ifdef GETSTYLE
cleanup_themes ();
#endif /* GETSTYLE */
}
void
check_widgetstyle (void)
{
proplist_t plnewstyle = WMCreatePLString ("NewStyle");
proplist_t value = WMGetFromPLDictionary (windowmaker, plnewstyle);
if (widgetstyle_item)
gtk_widget_set_sensitive (widgetstyle_item, !convert_bool (value));
WMReleasePropList (plnewstyle);
}
char *
get_pixmap_path (const char *name)
/*
* Guess filename of pixmap 'name'.
* Cycle through list of available paths or use absolute path
* if name [0] == '/' or '~'.
*
* Return value:
* string with pixmap path on success
* NULL if pixmap not found
*/
{
if (name [0] == '/' || name [0] == '~') /* absolute path ? */
{
FILE *file;
char *path = expand_tilde (name);
file = fopen (path, "r");
if (!file)
{
Free (path);
return NULL;
}
else
{
fclose (file);
return path;
}
}
else
{
unsigned n;
char *found = NULL;
proplist_t plpath = WMCreatePLString ("PixmapPath");
proplist_t pixmap_path = WMGetFromPLDictionary (windowmaker, plpath);
WMReleasePropList (plpath);
for (n = 0; n < WMGetPropListItemCount (pixmap_path) && !found; n++)
{
FILE *file;
char *path = expand_tilde (WMGetFromPLString (WMGetFromPLArray (pixmap_path,
n)));
char *filename = g_strconcat (path, "/", name, NULL);
Free (path);
file = fopen (filename, "r");
if (file)
{
found = filename;
fclose (file);
}
else
Free (filename);
}
return found;
}
}
GtkWidget *
make_pixmap (const char *name, int width, int height, GtkWidget *pw)
/*
* Genearate a new pixmap widget with pixmap 'name' of maximum size
* 'max_width' x 'max_height'. If 'pw' is already valid (i.e., != NULL)
* just replace the pixmap of the widget.
*
* Return value:
* new or changed pixmap widget
*/
{
char *path = get_pixmap_path (name);
if (!path)
{
dialog_popup (DIALOG_ERROR, NULL, NULL,
_("Can't find pixmap\n'%s`\nin PixmapPath. Please update\n"
"your PixmapPath attribute."), name);
return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
}
#if defined(PREVIEWS) && !defined(CONVERT)
if (!pw && width > 0 && height > 0)
pw = make_image (PKGDATADIR "/black.xpm", width, height, pw);
pw = make_image (path, width, height, pw);
#else /* not PREVIEWS or CONVERT */
#ifdef HAVE_STAT
/*
* Don't load large XPM (may cause trouble with imlib)
*/
{
struct stat buffer;
if (strstr (path, ".xpm") && stat (path, &buffer) == 0
&& buffer.st_size > 65000) /* image too large */
{
Free (path);
return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
}
}
#endif /* HAVE_STAT */
{
GdkBitmap *mask = NULL;
GdkPixmap *pixmap = NULL;
#ifdef HAVE_IMLIB
if (use_imlib)
{
GdkImlibImage *image;
image = gdk_imlib_load_image (path);
if (image)
{
if (width <= 0)
width = image->rgb_width;
if (height <= 0)
height = image->rgb_height;
if (image->rgb_width > width || image->rgb_height > height)
{
if (height * image->rgb_width > width * image->rgb_height)
height = width * image->rgb_height / image->rgb_width;
else
width = height * image->rgb_width / image->rgb_height;
}
gdk_imlib_render (image, max (width, 22), max (height, 22));
pixmap = gdk_imlib_move_image (image);
mask = gdk_imlib_move_mask (image);
if (strchr (g_basename (path), '.')) /* don't cache x-of-day */
gdk_imlib_destroy_image (image);
else
gdk_imlib_kill_image (image);
}
}
else
#else /* not HAVE_IMLIB */
pixmap
= gdk_pixmap_create_from_xpm (main_window->window, &mask,
background, PKGDATADIR "/black.xpm");
#endif /* not HAVE_IMLIB */
if (!pixmap) /* pixmap not found or unknown format */
{
static bool_t error_message = NO;
if (!error_message)
{
dialog_popup (DIALOG_ERROR, NULL, NULL,
_("Unable to display pixmap\n'%s`\n"
"(format not supported).\n"
"See stderr for subsequent messages."), path);
error_message = YES;
}
else
warning (_("Can't display pixmap '%s`."), path);
Free (path);
return make_pixmap (PKGDATADIR "/black.xpm", width, height, pw);
}
Free (path);
if (pw)
gtk_pixmap_set (GTK_PIXMAP (pw), pixmap, mask);
else
{
pw = gtk_pixmap_new (pixmap, mask);
gtk_widget_show (pw);
}
}
#endif /* not PREVIEWS or CONVERT */
return pw;
}
gint
quit (GtkWidget *widget, gpointer ptr)
/*
* Return from gtk_main () loop, i.e. leave the application.
* Before quitting ask for confirmation.
*
* No return value.
*/
{
if (changed || rootmenu_changed ())
{
quit_and_save_popup (_("Some values are modified.\n"
"Do you want to save them before quitting?"),
save_config_file, (gpointer) "quit");
return TRUE;
}
else
{
gtk_main_quit ();
return TRUE; /* do not delete window */
}
}
static void
quit_and_save_popup (char *question,
void (*save_function) (GtkWidget *, gpointer),
gpointer dataptr)
/*
* Popup dialog to ensure that current process is not killed until
* user confirmation.
* 'question' is the text to be displayed.
* 'save_function' is called in case user confirms saving.
* 'dataptr' argument is passed to 'save_function'.
*
* No return value.
*/
{
GtkWidget *hbox;
GtkWidget *window, *button;
window = gtk_dialog_new ();
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
gtk_window_set_title (GTK_WINDOW (window), _("Save before quitting?"));
gtk_widget_realize (window);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (gtk_false), NULL);
gtk_signal_connect_object (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
GTK_OBJECT (window));
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox,
FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
gtk_box_pack_start (GTK_BOX (hbox),
gtk_pixmap_new (p_array [P_INFO].pixmap,
p_array [P_INFO].mask),
TRUE, FALSE, 5);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (question), TRUE, TRUE, 5);
button = gtk_button_new_with_label (_("Yes"));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
TRUE, TRUE, 10);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (save_function), dataptr);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (window));
button = gtk_button_new_with_label (_("No"));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
TRUE, TRUE, 10);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
button = gtk_button_new_with_label (_("Cancel"));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
TRUE, TRUE, 10);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (window));
gtk_widget_show_all (window);
}
void
save_config_file (GtkWidget *widget, gpointer ptr)
/*
* Save 'WindowMaker' file if attributes have been changed.
*
* No return value.
*
* Side effects:
* 'changed' is set to FALSE
*/
{
if (!save_rootmenu ())
return;
if (changed)
{
proplist_t newwm = WMCreatePLDictionary (NULL, NULL, NULL);
/*
* Compare user attributes with system attributes
*/
{
proplist_t all_keys = WMGetPLDictionaryKeys (windowmaker) ;
unsigned n;
for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
{
proplist_t user;
proplist_t key = WMGetFromPLArray (all_keys, n);
user = WMGetFromPLDictionary (windowmaker, key);
if (WMGetFromPLDictionary (plist_changed, key))
WMPutInPLDictionary (newwm, key, WMDeepCopyPropList (user));
}
WMReleasePropList (all_keys);
}
if (WMWritePropListToFile (newwm, orig_wmaker_fname, YES))
{
changed = NO;
message (_("Window Maker config file '%s' saved."),
orig_wmaker_fname);
}
else
{
dialog_popup (DIALOG_ERROR, NULL, NULL,
_("Can't write to Window Maker file\n`%s'."),
orig_wmaker_fname);
return;
}
WMReleasePropList (newwm);
}
enable_revert ();
toggle_save (FALSE, NULL);
if (ptr && streq (ptr, "quit"))
gtk_main_quit ();
}
/*****************************************************************************
private code
*****************************************************************************/
static int
compare_fn (const void *p1, const void *p2)
{ return strcmp(((names_t *)p1)->intlname, ((names_t *)p2)->intlname); }
static void
appearance_container (proplist_t type, proplist_t thispanel,
GList **options, GtkWidget *box)
/*
* Gererate sub-containers for each appearance sub-panel.
*/
{
proplist_t subentries = WMGetPLDictionaryKeys (type);
GtkWidget *subbook = gtk_notebook_new ();
proplist_t plinfo = WMCreatePLString ("Info");
proplist_t plfont = WMCreatePLString ("Fontbox");
proplist_t pltexture = WMCreatePLString ("Texturebox");
proplist_t plcolor = WMCreatePLString ("Colorbox");
proplist_t plwidget = WMCreatePLString ("Widget");
proplist_t pltype = WMCreatePLString ("Type");
proplist_t plicon = WMCreatePLString ("Icon");
unsigned i;
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (subbook), TRUE);
gtk_notebook_set_scrollable (GTK_NOTEBOOK (subbook), TRUE);
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (subbook), GTK_POS_TOP);
gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (subbook), TRUE);
gtk_box_pack_start (GTK_BOX (box), subbook, TRUE, TRUE, 0);
gtk_container_set_border_width (GTK_CONTAINER (subbook), 10);
gtk_widget_show_all (subbook);
while (gtk_events_pending())
gtk_main_iteration();
for (i = 0; i < WMGetPropListItemCount (subentries); i++)
{
GtkWidget *subpage;
proplist_t thissub = WMGetFromPLArray (subentries, i);
proplist_t subentry = WMGetFromPLDictionary (type, thissub);
proplist_t subinfo = WMGetFromPLDictionary (subentry, plinfo);
proplist_t subicon = WMGetFromPLDictionary (subentry, plicon);
proplist_t subtype = WMGetFromPLDictionary (subentry, pltype);
char *path = NULL;
if (subicon && WMIsPLString (subicon)) /* subsubsections ? */
path = g_strconcat (PKGDATADIR, "/",
WMGetFromPLString (subicon), NULL);
subpage = create_page (GTK_NOTEBOOK (subbook),
D_(WMGetFromPLString (subinfo)), path, FALSE);
if (path)
Free (path);
{
proplist_t data;
data = WMCreatePLDataWithBytes ((unsigned char *) &subpage,
sizeof (GtkWidget *));
WMPutInPLDictionary (subentry, plwidget, data);
WMReleasePropList (data);
}
while (gtk_events_pending())
gtk_main_iteration();
/*
* Add subboxes for color, texture and font
*/
{
GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
GtkWidget *nw_hbox = gtk_hbox_new (FALSE, 0);
GtkWidget *color_frame = gtk_hbox_new (FALSE, 0);
GtkWidget *texture_frame = gtk_hbox_new (FALSE, 0);
GtkWidget *color_box = gtk_hbox_new (FALSE, 0);
GtkWidget *texture_box = gtk_vbox_new (FALSE, 0);
GtkWidget *hbox;
proplist_t color_data;
proplist_t texture_data;
proplist_t font_data;
gtk_container_add (GTK_CONTAINER (subpage), vbox);
/*
* Overall boxes
*/
gtk_box_pack_start (GTK_BOX (vbox), nw_hbox,
FALSE, TRUE, 5);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), color_frame,
TRUE, TRUE, 5);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
gtk_box_pack_start (GTK_BOX (hbox), texture_frame,
TRUE, TRUE, 5);
while (gtk_events_pending())
gtk_main_iteration();
/*
* Color box
*/
{
GtkWidget *frame = gtk_frame_new (_("Colors"));
GtkWidget *box = color_box;
gtk_box_pack_start (GTK_BOX (color_frame), frame,
TRUE, TRUE, 0);
gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
gtk_container_add (GTK_CONTAINER (frame), box);
gtk_container_set_border_width (GTK_CONTAINER (box), 5);
color_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
sizeof (GtkWidget *));
gtk_object_set_user_data (GTK_OBJECT (box),
color_frame);
}
while (gtk_events_pending())
gtk_main_iteration();
/*
* Texture box
*/
{
GtkWidget *frame = gtk_frame_new (_("Texture"));
GtkWidget *box = texture_box;
gtk_box_pack_start (GTK_BOX (texture_frame), frame,
TRUE, TRUE, 0);
gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5);
gtk_container_add (GTK_CONTAINER (frame), box);
texture_data = WMCreatePLDataWithBytes ((unsigned char *) &box,
sizeof (GtkWidget *));
gtk_object_set_user_data (GTK_OBJECT (box),
texture_frame);
}
/*
* Font box
*/
{
font_data = WMCreatePLDataWithBytes ((unsigned char *) &nw_hbox,
sizeof (GtkWidget *));
}
gtk_widget_show_all (subpage);
gtk_widget_hide (color_frame);
gtk_widget_hide (texture_frame);
while (gtk_events_pending())
gtk_main_iteration();
/*
* Make option box with subsubsections and subboxes
* for color, texture and font
*/
if (subtype && WMIsPLDictionary (subtype))
{
proplist_t ssentries = WMGetPLDictionaryKeys (subtype);
unsigned k;
char *path;
GtkWidget *option_menu = gtk_option_menu_new ();
GtkWidget *menu = gtk_menu_new ();
path = g_strconcat (WMGetFromPLString (thispanel), "/",
WMGetFromPLString (thissub), NULL);
for (k = 0; k < WMGetPropListItemCount (ssentries); k++)
{
proplist_t thisss;
proplist_t ssentry;
proplist_t ssinfo;
GtkWidget *menu_item;
thisss = WMGetFromPLArray (ssentries, k);
ssentry = WMGetFromPLDictionary (subtype, thisss);
ssinfo = WMGetFromPLDictionary (ssentry, plinfo);
menu_item = gtk_menu_item_new_with_label (D_(WMGetFromPLString (ssinfo)));
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
GTK_SIGNAL_FUNC (switch_subentries),
path);
gtk_object_set_user_data (GTK_OBJECT (menu_item),
(gpointer) WMGetFromPLString (thisss));
gtk_menu_append (GTK_MENU (menu), menu_item);
gtk_widget_show (menu_item);
WMPutInPLDictionary (ssentry, plcolor,
color_data);
WMPutInPLDictionary (ssentry, pltexture,
texture_data);
WMPutInPLDictionary (ssentry, plfont,
font_data);
if (strcaseeq (WMGetFromPLString (thisss), "Widget"))
widgetstyle_item = menu_item;
}
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu),
menu);
gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), 0);
gtk_widget_show (option_menu);
*options = g_list_append (*options, option_menu);
while (gtk_events_pending())
gtk_main_iteration();
{
GtkWidget *frame;
GtkWidget *box = gtk_hbox_new (TRUE, 0);
frame = gtk_frame_new (D_(WMGetFromPLString (subinfo)));
gtk_frame_set_label_align (GTK_FRAME (frame),
0.5, 0.5);
gtk_container_set_border_width (GTK_CONTAINER (box), 5);
gtk_container_add (GTK_CONTAINER (frame), box);
gtk_box_pack_start (GTK_BOX (box), option_menu,
TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (nw_hbox), frame,
FALSE, TRUE, 5);
gtk_widget_show_all (frame);
}
while (gtk_events_pending())
gtk_main_iteration();
}
else
{
WMPutInPLDictionary (subentry, plcolor,
color_data);
WMPutInPLDictionary (subentry, pltexture,
texture_data);
WMPutInPLDictionary (subentry, plfont,
font_data);
}
WMReleasePropList (color_data);
WMReleasePropList (texture_data);
WMReleasePropList (font_data);
}
}
WMReleasePropList (subentries);
WMReleasePropList (plinfo);
WMReleasePropList (pltype);
WMReleasePropList (plicon);
WMReleasePropList (plwidget);
WMReleasePropList (plcolor);
WMReleasePropList (plfont);
WMReleasePropList (pltexture);
}
static void
init_option_menu (gpointer data, gpointer user_data)
{
GtkOptionMenu *omenu = GTK_OPTION_MENU (data);
GtkMenu *menu = GTK_MENU (gtk_option_menu_get_menu (omenu));
GtkWidget *item = gtk_menu_get_active (menu);
if (item)
gtk_menu_item_activate (GTK_MENU_ITEM (item));
}
static GtkWidget *
create_page (GtkNotebook *notebook, const char *name, const char *pixmap_name,
bool_t horizontal)
/*
* Create a new group notebook page and append it to the given 'notebook'.
* 'name' is the notebook label and 'pm' is the pixmap identifier.
*
* Return value:
* container of label and pixmap
*/
{
GtkWidget *vbox = gtk_vbox_new (FALSE, 5);
GtkWidget *label_box = NULL;
GtkWidget *scrolled = NULL;
if (name || pixmap_name)
{
label_box = horizontal ? gtk_hbox_new (FALSE, 5) : gtk_vbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (label_box),
horizontal ? 0 : 5);
if (pixmap_name)
{
GdkPixmap *pixmap;
GdkBitmap *mask;
pixmap = gdk_pixmap_create_from_xpm (main_window->window, &mask,
background, pixmap_name);
if (pixmap)
gtk_box_pack_start (GTK_BOX (label_box),
gtk_pixmap_new (pixmap, mask), FALSE, TRUE, 0);
}
if (name)
gtk_box_pack_start (GTK_BOX (label_box), gtk_label_new (name),
TRUE, TRUE, 0);
gtk_widget_show_all (label_box);
}
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
vbox);
gtk_notebook_append_page_menu (notebook, scrolled, label_box, NULL);
gtk_widget_show_all (scrolled);
return vbox;
}
static void
switch_subentries (GtkWidget *widget, gpointer ptr)
/*
* Show only widgets of chosen subsubentry
*/
{
unsigned n;
proplist_t all_keys = WMGetPLDictionaryKeys (wmconfig);
proplist_t plgrp = WMCreatePLString ("Group");
proplist_t plwidget = WMCreatePLString ("Widget");
char *text = gtk_object_get_user_data (GTK_OBJECT (widget));
char *prefix = (char *) ptr;
char *path = g_strconcat (prefix, "/", text, NULL);
for (n = 0; n < WMGetPropListItemCount (all_keys); n++)
{
proplist_t key = WMGetFromPLArray (all_keys, n);
proplist_t keydef = WMGetFromPLDictionary (wmconfig, key);
proplist_t data = WMGetFromPLDictionary (keydef, plwidget);
if (data)
{
proplist_t group = WMGetFromPLDictionary (keydef, plgrp);
GtkWidget *widget = * (GtkWidget **) WMGetPLDataBytes (data);
if (strcaseeq (path, WMGetFromPLString (group)))
gtk_widget_show (widget);
else
{
char *right = strrchr (path, '/');
/* g_strncasecmp: only in GTK+1.1.x */
{
char *str1 = g_strdup (path);
char *str2 = g_strdup (WMGetFromPLString (group));
str1 [right - path] = 0;
str2 [right - path] = 0;
if (g_strcasecmp (str1, str2) == 0)
gtk_widget_hide (widget);
Free (str1);
Free (str2);
}
}
}
}
WMReleasePropList (plwidget);
WMReleasePropList (plgrp);
}
syntax highlighted by Code2HTML, v. 0.9.1