#!/usr/bin/perl -w

#
# This program and all associated files are copyright (C) 1998
# Richard Hestilow and are available for use under the terms of the
# GNU GPL. Details of the GPL are in the file COPYING which should
# be included with the distribution.
#
# This program has NO WARRANTY; see COPYING for details.

 
use Gtk;

$VERSION = "0.1.6";

$focus_now = "Click to focus";
$focus_now_nbr = 1;

%focus_methods = ("Click to raise",
"ClickToFocus=1\nRaiseOnFocus=1\nFocusOnMap=1\n",
"Click to focus", 
"ClickToFocus=1\nRaiseOnFocus=0\nRaiseOnClickClient=0\nFocusOnMap=1\n",
"Pointer focus", "ClickToFocus=0\nRaiseOnFocus=0\n");

%taskbar_date = ("Time format", "TimeFormat", "Date Format", "DateFormat",
"Path to icons", "IconPath");

%fonts = ("Title", "TitleFontName", "Menu", "MenuFontName", "Status",
"StatusFontName", "Quick switch", "QuickSwitchFontName", "Normal Taskbar", 
"NormalTaskBarFontName", "Active Taskbar", "ActiveTaskBarFontName", 
"Window list", "WindowListFontName", "Tooltip", "ToolTipFontName",
"Clock", "ClockFontName");

%taskbar_commands = ("Mail", "MailCommand", "Lock", "LockCommand", "Clock",
"ClockCommand", "Run", "RunCommand");

%taskbar_boolean = ("Show Taskbar", "ShowTaskBar", "Auto Hide", "TaskBarAutoHide",
"Show clock", "TaskBarShowClock", "LED clock", "TaskBarClockLeds", 
"Show mailbox status", "TaskBarShowMailboxStatus", "Beep on new mail",
"TaskBarMailboxStatusBeepOnNewMail", "Taskbar on top", "TaskBarAtTop", 
"Show all windows", "TaskBarShowAllWindows", "Show workspaces", 
"TaskBarShowWorkspaces", "Show \"Start\" menu", "TaskBarShowStartMenu", 
"Show \"Window List\" menu","TaskBarShowWindowListMenu", 
"Double-height Taskbar", "TaskBarDoubleHeight", "Menus track mouse", 
"MenuMouseTracking");

%windows_boolean = ("Automatically raise", "AutoRaise", "Pointer colormap",
"PointerColormap","Size Maximized", "SizeMaximized", "Opaque move",
"OpaqueMove", "Opaque Resize", "OpaqueResize", "Manual Placement",
"ManualPlacement", "Delay Pointer Focus", "DelayPointerFocus",
"Use Mouse Wheel", "UseMouseWheel", "Alt-tab for all windows", 
"QuickSwitchToMinimized", "Warp Pointer", "WarpPointer", "Show close button",
"ShowXButton", "Minimize to desktop", "MinimizeToDesktop", "Win95 keys",
"Win95Keys");

%windows_sizes = ("Dialog Border Length", "DlgBorderSizeX", 
"Dialog Border Height", "DlgBorderSizeY", "Normal Border Length", 
"BorderSizeX", "Normal Border Height", "BorderSizeY", "Corner Length", 
"CornerSizeX", "Corner Height", "CornerSizeY", "Title bar height", 
"TitleBarHeight", "Pointer Focus Delay", "PointerFocusDelay", 
"Double click time", "MultiClickTime", "Tooltip delay time", 
"ToolTipDelay");

%entries = ();

@numbers = (\%taskbar_boolean, \%windows_boolean, \%windows_sizes);
@strings = (\%taskbar_date, \%fonts, \%taskbar_commands);

$home = $ENV{'HOME'};
@locations = ("/etc/X11/icewm", "/usr/X11R6/lib/X11/icewm",
"/usr/local/lib/X11/icewm");

foreach $place (@locations) { # find system icewm dir 
	if (-r "$place" and -r "$place/preferences") {
		$sys_loc = $place;
		last;
	}
}

foreach $place (@locations) { # find system themes dir
	if (-r "$place" and -r "$place/themes") {
		$theme_loc = $place;
		last;
	}
}

parse_pref_file();

Gtk->init;
$window = new Gtk::Window -toplevel;
$window->signal_connect("destroy", \&quit_cb, NULL);
$window->set_title("IceWM Configurator $VERSION");

$notebook = create_notebook();

$main_vbox = new Gtk::VBox(0, 5);
$main_vbox->pack_start($notebook, 1, 0, 0);
$label = new Gtk::Label(
"Note: You will have to restart IceWM for the changes to take effect");
$main_vbox->pack_start($label, 1, 0, 5);
$separator = new Gtk::HSeparator;
$main_vbox->pack_start($separator, 1, 0, 0);

$hbox = new Gtk::HBox(1, 5);
$button = new Gtk::Button("Ok");
$button->signal_connect("clicked", sub { save_cb(); quit_cb()});
$hbox->pack_start($button, 1, 1, 5);
$button = new Gtk::Button("Save");
$button->signal_connect("clicked", \&save_cb, NULL);
$hbox->pack_start($button, 1, 1, 5);
$button = new Gtk::Button("Cancel");
$button->signal_connect("clicked", \&quit_cb, NULL);
$hbox->pack_start($button, 1, 1, 5);
$main_vbox->pack_start($hbox, 1, 0, 5);
$window->add($main_vbox);
$window->show_all;
Gtk->main;

sub quit_cb {
Gtk->main_quit;
}

sub create_notebook {
my($notebook);
my($hbox, $label);
$notebook = new Gtk::Notebook;

$notebook->append_page( create_tb_page() );
$notebook->append_page( create_font_page() );
$notebook->append_page( create_wins_page() );
$notebook->append_page( create_misc_page() );
return $notebook;
}

sub create_tb_page {
my($vbox, $label, $option, $button, $separator, $vbox2, $frame, $entry);

$vbox = new Gtk::VBox(0, 3);
$hbox = new Gtk::HBox(0, 3);
foreach $option (sort keys %taskbar_boolean) {
	$button = new Gtk::CheckButton($option);
	if (defined(${$taskbar_boolean{$option}})) {
		if (${$taskbar_boolean{$option}}) {
			$button->set_state(1);
		}
	} else {
		${$taskbar_boolean{$option}} = 0;
	}

	$button->signal_connect("clicked", \&flip,
		\${$taskbar_boolean{$option}});
	
	$vbox->pack_start($button, 1, 0, 0);	
}
$hbox->pack_start($vbox, 1, 0, 0);

$separator = new Gtk::VSeparator;
$hbox->pack_start($separator, 1, 0, 0);

$vbox = new Gtk::VBox(0, 3);
$vbox2 = new Gtk::VBox(0, 3);
$frame= new Gtk::Frame("Commands");
foreach $option (sort keys %taskbar_commands) {
	$hbox2 = new Gtk::HBox(1, 3);
	$label = new Gtk::Label($option);
	$entries{$taskbar_commands{$option}} = new Gtk::Entry;
	$entry = \$entries{$taskbar_commands{$option}};
	$hbox2->pack_start($label, 1, 0, 0);
	$hbox2->pack_start($$entry, 1, 0, 0);
	if (defined(${$taskbar_commands{$option}})) {
		$$entry->set_text(${$taskbar_commands{$option}});
	}
	$vbox2->pack_start($hbox2, 1, 0, 0);
}
$frame->add($vbox2);
$vbox->pack_start($frame, 1, 0, 0);

foreach $option (sort keys %taskbar_date) {
	$hbox2 = new Gtk::HBox(1, 3);
	$label = new Gtk::Label($option);
	$entries{$taskbar_date{$option}} = new Gtk::Entry;
	$entry = \$entries{$taskbar_date{$option}};
	$hbox2->pack_start($label, 1, 0, 0);
	$hbox2->pack_start($$entry, 1, 0, 0);
	if (defined(${$taskbar_date{$option}})) {
		$$entry->set_text(${$taskbar_date{$option}});
	}
	$vbox->pack_start($hbox2, 1, 0, 0);
}

$hbox->pack_start($vbox, 1, 0, 0);

$label = new Gtk::Label("Taskbar");

return ($hbox, $label);
}

sub create_font_page {
my($vbox, $label, $option, $hbox, $entry);

$vbox = new Gtk::VBox(1, 5);
foreach $option (sort keys %fonts) {
	$hbox = new Gtk::HBox(1, 3);
	$label = new Gtk::Label($option);
	$hbox->pack_start($label, 1, 0, 0);
	$entries{$fonts{$option}}= new Gtk::Entry;
	$entry = \$entries{$fonts{$option}};
	if (defined(${$fonts{$option}})) {
		$$entry->set_text(${$fonts{$option}});
	}
	$hbox->pack_start($$entry, 1, 0, 0);
	$vbox->pack_start($hbox, 1, 0, 0);
}
$label = new Gtk::Label("Fonts");

return ($vbox, $label);
}

sub create_wins_page {
my($vbox, $label, $hbox, $option_menu, $menu, $menuitem, $method);
my($option, $separator, $entry);

$label = new Gtk::Label("Focus method:");
$hbox = new Gtk::HBox(0, 3);
$hbox->pack_start($label, 1, 0, 0);
$option_menu= new Gtk::OptionMenu;
$menu = new Gtk::Menu;
$menuitem = undef;
foreach $method (sort keys %focus_methods) {
	$menuitem = new Gtk::MenuItem ($method);
	$menuitem->signal_connect("activate", \&menu_changed, $method);
	$menuitem->show();
	$menu->append($menuitem);
}
$option_menu->set_menu($menu);
$option_menu->set_history($focus_now_nbr);
$hbox->pack_start($option_menu, 1, 0, 0);
$vbox = new Gtk::VBox(0, 3);
$vbox->pack_start($hbox, 1, 0, 0);
$hbox = new Gtk::HBox(0, 3);
foreach $option (sort keys %windows_boolean) {
	$button = new Gtk::CheckButton($option);
	if (defined(${$windows_boolean{$option}})) {
		if (${$windows_boolean{$option}}) {
			$button->set_state(1);
		}
	} else {
		${$windows_boolean{$option}} = 0;
	}
	$button->signal_connect("clicked", \&flip, 
				\${$windows_boolean{$option}});

	$vbox->pack_start($button, 1, 0, 0);
}
$hbox->pack_start($vbox, 1, 0, 0);
$separator = new Gtk::VSeparator;
$hbox->pack_start($separator, 1, 0, 0);
$vbox = new Gtk::VBox(0, 5);
foreach $option (sort keys %windows_sizes) {
	$hbox2 = new Gtk::HBox(1, 3);
	$label = new Gtk::Label($option);
	$hbox2->pack_start($label, 1, 0, 0);
	$entries{$windows_sizes{$option}} = new Gtk::Entry;
	$entry = \$entries{$windows_sizes{$option}};
	if (defined(${$windows_sizes{$option}})) {
		$$entry->set_text(${$windows_sizes{$option}});
	}
	$hbox2->pack_start($$entry, 1, 0, 0);
	$vbox->pack_start($hbox2, 1, 0, 0);
}
$hbox->pack_start($vbox, 1, 0, 0);

$label = new Gtk::Label("Windows");
return ($hbox, $label);
}

sub create_misc_page {
my($vbox, $hbox, $label, $entry, $scrolled_win, $vbox2);
my($space, $button, $frame);

$vbox = new Gtk::VBox(0, 3);
$vbox2 = new Gtk::VBox(1, 3);
$hbox = new Gtk::HBox(1, 3);
$label = new Gtk::Label("Theme");
$entries{"Theme"} = new Gtk::Entry;
$entry = \$entries{"Theme"};

if (defined($Theme)) {
	$$entry->set_text($Theme);
}

$button = new Gtk::Button("Browse");
$button->signal_connect("clicked", \&create_theme_filesel, $entry);
$hbox->pack_start($label, 1, 0, 0);
$hbox->pack_start($$entry, 1, 0, 0);
$hbox->pack_start($button, 1, 0, 0);
$vbox2->pack_start($hbox, 1, 0, 0);


$hbox = new Gtk::HBox(1, 3);
$label = new Gtk::Label("Desktop Background Image");
$entries{"BgImage"} = new Gtk::Entry;
$entry = \$entries{"BgImage"};

if (defined($DesktopBackgroundImage)) {
	$$entry->set_text($DesktopBackgroundImage);
}

$button = new Gtk::Button("Browse");
$button->signal_connect("clicked", \&create_bgimg_filesel, $entry);
$hbox->pack_start($label, 1, 0, 0);
$hbox->pack_start($$entry, 1, 0, 0);
$hbox->pack_start($button, 1, 0, 0);

$vbox2->pack_start($hbox, 1, 0, 0);

$hbox = new Gtk::HBox(1, 5);
$label = new Gtk::Label("Desktop Background Color");
$entries{"BgColor"} = new Gtk::Entry;
$entry = \$entries{"BgColor"};
if (defined($DesktopBackgroundColor)) {
	$$entry->set_text($DesktopBackgroundColor);
}
$button = new Gtk::Button("Select");
$button->signal_connect("clicked", \&create_bgclr_clrsel, $entry);
$hbox->pack_start($label, 1, 0, 0);
$hbox->pack_start($$entry, 1, 0, 0);
$hbox->pack_start($button, 1, 0, 0);
$vbox2->pack_start($hbox, 1, 0, 0);

$vbox->pack_start($vbox2, 1, 0, 0);

$vbox2 = new Gtk::VBox(0, 3);
$scrolled_win = new Gtk::ScrolledWindow(undef, undef);
$scrolled_win->set_policy(-automatic, -automatic);
$ws_list = new Gtk::List;
$ws_list->set_selection_mode(-multiple);
$ws_list->set_selection_mode(-browse);
foreach $space (@Workspaces) {
	$list_item = new Gtk::ListItem($space);
	$ws_list->add($list_item);
}
$scrolled_win->add($ws_list);
$vbox2->pack_start($scrolled_win, 1, 0, 0);
$hbox = new Gtk::HBox(1, 3);
$button = new Gtk::Button("Add");
$button->can_focus(0);
$button->signal_connect("clicked", \&ws_list_add, $ws_list);
$hbox->pack_start($button, 1, 0, 0);
$button = new Gtk::Button("Remove");
$button->can_focus(0);
$button->signal_connect("clicked", \&ws_list_remove, $ws_list);
$hbox->pack_start($button, 1, 0, 0);
$vbox2->pack_start($hbox, 1, 0, 0);
$frame = new Gtk::Frame("Workspaces");
$frame->add($vbox2);
$vbox->pack_start($frame, 1, 0, 0);

$label = new Gtk::Label("Misc");
return ($vbox, $label);
}

sub bgclr_clrsel_ok {
	my($widget, $data) = @_;
	my($dlg) = $$data{"win"};
	my(@color) = $$dlg->colorsel->get_color;
	my($entry) = $$data{"entry"};
	
	my($rgb) = "rgb:";
	my(@rgbs);	
	my($tmp);
	for(my($i)=0;$i<3;$i++) {
		$tmp = int (255 * $color[$i]);
		if ($tmp > 15) {
			push @rgbs, sprintf("%x", $tmp);
		} else {
			push @rgbs, sprintf("0%x", $tmp);
		}
	}
	
	$rgb .= $rgbs[0] . "/" . $rgbs[1] . "/" . $rgbs[2];
	$$entry->set_text($rgb);
}

sub create_bgclr_clrsel {
	# mostly stolen from test.pl
	
	my($widget, $data) = @_;
	my($cs_window);

	set_install_cmap Gtk::Preview 1;
	Gtk::Widget->push_visual(Gtk::Preview->get_visual);
	Gtk::Widget->push_colormap(Gtk::Preview->get_cmap);

	$cs_window = new Gtk::ColorSelectionDialog "Please select a color";

	$cs_window->colorsel->set_opacity(1);
	$cs_window->colorsel->set_update_policy(-continuous);
	$cs_window->position(-mouse);
	$cs_window->signal_connect("destroy", \&destroy_window, \$cs_window);
	$cs_window->ok_button->signal_connect("clicked", \&bgclr_clrsel_ok ,
				{ "win" => \$cs_window,	"entry" => $data});
	$cs_window->cancel_button->signal_connect("destroy", \&destroy_window,
						\$cs_window);
	pop_colormap Gtk::Widget;
	pop_visual Gtk::Widget;
	show $cs_window;
}

sub parse_pref_file {

# WARNING! This code is naive and lazy. It probably should not be run as root.
# I take no responsibility for things it does.


if ((!(-d "$home/.icewm")) or (!(-e "$home/.icewm/preferences"))) {
			if (!(-d "$home/.icewm")) {
				print ".icewm directory not found. creating...\n";
				system("mkdir $home/.icewm");
			}
			if (!(-e "$home/.icewm/preferences")) {
				print "preferences file not found, creating...\n";
				system("cp $sys_loc/preferences $home/.icewm/");
				system("chmod 644 $home/.icewm/preferences");
			}
		}

 

open(PREFS, "$home/.icewm/preferences");

# this routine converts the prefs to perl and eval's it. This is somewhat 
# dangerous. Not very, however, since all it's doing is assigning values to 
# variables
	
while (defined($line = <PREFS>)) {
	chomp($line);
	if ($line =~ /^\s*\w+\=\s*\".*?\"$/) {
		if ($line =~ /\s*AddWorkspace\=\"(.*?)\"$/) {
			push @Workspaces, $1;
		}
		else {
			eval "\$$line\;\n";
		}
	}
	elsif ($line =~ /(\s*\w+\=)(\s*[^"]+$)/) {
		eval "\$$1\"$2\"\;\n"
	}
}

if (defined($RaiseOnClickClient)) {} # Just to shut perl up.

if    ($ClickToFocus==1 && $RaiseOnFocus==1 && $FocusOnMap==1) 
	{$focus_now="Click to raise"; $focus_now_nbr=1;}  
elsif ($ClickToFocus==1 && $RaiseOnFocus==0 && $RaiseOnClickClient==0 && $FocusOnMap==1) 
	{$focus_now="Click to focus"; $focus_now_nbr=0;}
elsif ($ClickToFocus==0 && $RaiseOnFocus==0) 
	{$focus_now="Pointer focus"; $focus_now_nbr=2;}
close PREFS;
}

sub create_bgimg_filesel {
	my($widget, $data) = @_;
	my($fs_window);
	$fs_window = new Gtk::FileSelection("Please select an image");
	$fs_window->signal_connect("delete_event", \&destroy_window,
					\$fs_window);
	$fs_window->ok_button->signal_connect("clicked", \&bgimg_filesel_ok,
						\$fs_window);
	$fs_window->cancel_button->signal_connect("clicked", \&destroy_window,
					\$fs_window);
	if (defined($DesktopBackgroundImage)) {
		$fs_window->set_filename("$DesktopBackgroundImage");
	}
	show $fs_window;
}

sub bgimg_filesel_ok {
	my($widget, $data) = @_;
	my($text, $entry);
	my($fs_window) = $$data;

	$entry = \$entries{"BgImage"};
	$text = $fs_window->get_filename();
	$$entry->set_text($text);
	destroy $fs_window;
}

sub create_theme_filesel {
	my($widget, $data)=@_;
	my($fs_window);
	
	$fs_window = new Gtk::FileSelection("Please select a theme");
	$fs_window->signal_connect("delete_event", \&destroy_window,
		\$fs_window);
	$fs_window->ok_button->signal_connect("clicked", \&theme_filesel_ok,
		\$fs_window);
	$fs_window->cancel_button->signal_connect("clicked", sub {destroy
		$fs_window});
	if (defined($Theme)) {
		$fs_window->set_filename("$theme_loc/themes/$Theme");
	}
	else {
		$fs_window->set_filename("$theme_loc/themes/*.theme");
	}
	
	show $fs_window;
}

sub destroy_window {
	my($widget, $windowref) = @_;
	$$windowref = undef;
}

sub theme_filesel_ok {
	my($widget, $data) = @_;
	my($text, $entry);
	my($fs_window) = $$data;
	$text = $fs_window->get_filename;
	if ($text =~ /.+\/(.+\/.+)$/) { # We actually want greedy matching.
		$Theme = $1;
	}
	$entry = \$entries{"Theme"};
	$$entry->set_text($Theme);
	destroy $fs_window;
}

sub save_cb {
open(PREFS, ">$home/.icewm/preferences");
print PREFS "# Generated by IceWM Configuration program $VERSION\n";

print PREFS "$focus_methods{$focus_now}\n";

foreach $option (sort keys %entries) {
	${$option} = $entries{$option}->get_text;
}

foreach $hashie (@numbers) {
	foreach $option (sort keys %$hashie) {
		if (defined(${$$hashie{$option}})) {
			print PREFS "$$hashie{$option}=${$$hashie{$option}}\n";
		}
	}
}
foreach $hashie (@strings) {
	foreach $option (sort keys %$hashie) {
		if (defined(${$$hashie{$option}})) {
			print PREFS "$$hashie{$option}=\"${$$hashie{$option}}\"\n";
		}
	}
}

$entry = \$entries{"BgColor"};
print PREFS "DesktopBackgroundColor=\"" . $$entry->get_text() . "\"\n";

$entry = \$entries{"BgImage"};
print PREFS "DesktopBackgroundImage=\"" . $$entry->get_text() . "\"\n";

$entry = \$entries{"Theme"};
$Theme=$$entry->get_text();
print PREFS "Theme=\"$Theme\"\n";

foreach $name (@Workspaces) {
	print PREFS "AddWorkspace=\"$name\"\n";
}

close PREFS;
}

sub flip {
my($widget, $data) = @_;
$$data = 1 - $$data;
}

sub ws_list_add {
my($widget, $data) = @_;
$ws_win = new Gtk::Window -toplevel;
$ws_win->set_title("New Workspace");
$vbox = new Gtk::VBox(0, 5);
$hbox = new Gtk::HBox(0, 5);
$label = new Gtk::Label("Workspace Name");
$entry = new Gtk::Entry;
$entry->signal_connect("activate", \&ws_add_ok, $entry);
$ws_win->set_focus($entry);
$hbox->pack_start($label, 1, 0, 0);
$hbox->pack_start($entry, 1, 0, 0);
$vbox->pack_start($hbox, 1, 0, 5);
$hbox = new Gtk::HBox(0, 5);

$vbox2 = new Gtk::VBox(0, 5);
$pend_type = 1;
$button = new Gtk::RadioButton("Prepend");
$button->signal_connect("clicked", sub {$pend_type = 0});
$vbox2->pack_start($button, 1, 0, 0);
$button = new Gtk::RadioButton("Append", $button);
$button->signal_connect("clicked", sub {$pend_type = 1});
$button->set_state(1);
$vbox2->pack_start($button, 1, 0, 0);
$vbox->pack_start($vbox2, 1, 0, 0);

$button = new Gtk::Button("Ok");
$button->signal_connect("clicked", \&ws_add_ok, $entry);
$hbox->pack_start($button, 1, 0, 0);
$button = new Gtk::Button("Cancel");
$button->signal_connect("clicked", sub {destroy $ws_win});
$hbox->pack_start($button, 1, 0, 0);
$vbox->pack_start($hbox, 1, 0, 5);
$ws_win->add($vbox);
$ws_win->show_all;
}

sub ws_add_ok {
my($widget, $data) = @_;
$listitem = new Gtk::ListItem($data->get_text);
$selection = $ws_list->selection;
if (defined($selection)) {
	$pos = $ws_list->child_position($selection);
}
else {
	$pos = 0;
	$pend_type = 0;
}

$ws_list->insert_items($pos + $pend_type, $listitem);
$listitem->show;
splice @Workspaces, $pos + $pend_type, 0, $data->get_text;
destroy $ws_win;
}

sub ws_list_remove {
my($widget, $data) = @_;
if (!(defined($data->selection))) {
	return;
}
	$name = $data->selection->children->get;

for($i=0;$i<@Workspaces;$i++) {		#I should probably find a better way
	if ($Workspaces[$i] eq $name) {	# of doing this
		splice(@Workspaces, $i, 1);
	}
}

$data->remove_items($data->selection);
}

sub menu_changed {
my($widget, $data) = @_;
$focus_now = $data;
}
