/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * 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-1307, USA
 */

#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdio.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include "../common/xchat.h"
#include "../common/fe.h"
#include "fe-gtk.h"
#include "menu.h"
#include "gtkutil.h"
#include "panel.h"
#include "pixmaps.h"
#include <gdk/gdkkeysyms.h>
#ifdef USE_PANEL
#include <applet-widget.h>
extern int nopanel;
extern GtkWidget *panel_applet, *panel_box, *panel_popup;
#endif
#include "xtext.h"

GtkWidget *main_window = 0;
GtkWidget *main_book;
GtkWidget *main_menu;
GtkWidget *main_menu_bar;

GtkStyle *normaltab_style = 0;
GtkStyle *redtab_style;
GtkStyle *bluetab_style;
GtkStyle *inputgad_style;

static char chan_flags[] = { 't', 'n', 's', 'i', 'p', 'm', 'l', 'k' };

extern struct session *current_tab, *menu_sess, *perl_sess;
extern struct xchatprefs prefs;
extern GSList *sess_list;
extern GSList *button_list;
extern GSList *serv_list;
extern GdkPixmap *channelwin_pix;
extern GdkFont *dialog_font_normal;
extern GdkFont *font_normal;
extern GdkColor colors[];
extern gint xchat_is_quitting;

extern void menu_showhide (session *sess, int force_hide);
extern void menu_newshell_set_palette (session *sess);
extern void nick_command_parse (session * sess, char *cmd, char *nick,
										  char *allnick);
extern void userlist_button_cb (GtkWidget * button, char *cmd);
extern void goto_url (void *unused, char *url);
extern void ascii_open (void);
extern int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1,
										char *d2, struct session *sess);
extern int handle_multiline (struct session *sess, char *cmd, int history,
									  int nocommand);
extern int kill_session_callback (struct session *sess);
extern gint gtk_kill_session_callback (GtkWidget *, struct session *sess);
extern void palette_alloc (GtkWidget * widget);
extern void menu_middlemenu (session *sess, GdkEventButton *event);
extern void menu_urlmenu (struct session *sess, GdkEventButton * event,
								  char *url);
extern void menu_hostmenu (struct session *sess, GdkEventButton * event,
									char *url);
extern void menu_chanmenu (struct session *sess, GdkEventButton * event,
									char *url);
extern void userlist_dnd_drop (GtkWidget *, GdkDragContext *, gint, gint,
										 GtkSelectionData *, guint, guint32,
										 struct session *);
extern int userlist_dnd_motion (GtkWidget *, GdkDragContext *, gint, gint,
										  guint);
extern int userlist_dnd_leave (GtkWidget *, GdkDragContext *, guint time);
extern int tcp_send_len (struct server *serv, char *buf, int len);
extern int tcp_send (struct server *serv, char *buf);
extern void menu_nickmenu (session *sess, GdkEventButton *event, char *nick);
extern void clear_user_list (struct session *sess);
extern GtkWidget *createmenus (void *app, struct session *sess, int bar);
extern void handle_inputgad (GtkWidget * igad, struct session *sess);
extern void my_gtk_entry_set_text (GtkWidget * wid, char *text,
											  struct session *sess);
extern struct session *new_dialog (struct session *sess);
extern void create_panel_widget ();
int key_handle_key_press (GtkWidget *, GdkEventKey *, gpointer);

static void userlist_button (GtkWidget * box, char *label, char *cmd,
									  struct session *sess, int a, int b, int c,
									  int d);
static void my_gtk_toggle_state (GtkWidget * wid, int state, char which,
											struct session *sess);
static void tree_update ();
void tree_default_style (struct session *sess);

struct relink_data
{
	GtkWidget *win, *hbox;
	gchar *ltitle;
	gchar *stitle;
	void (*close_callback) (GtkWidget *, void *);
	void *userdata;
};


void
maingui_showhide_topic (GtkWidget *button, session *sess)
{
	if (GTK_WIDGET_VISIBLE (sess->gui->tbox))
	{
		gtk_widget_hide (sess->gui->tbox);
		prefs.topicbar = 0;
	} else
	{
		gtk_widget_show (sess->gui->tbox);
		prefs.topicbar = 1;
	}
}

static void
maingui_set_icon (GtkWidget *win)
{
	gtkutil_set_icon (win->window, pix_xchat_mini, mask_xchat_mini);

	gdk_window_set_icon (win->window, NULL, pix_xchat, mask_xchat);
	gdk_window_set_icon_name (win->window, PACKAGE);
}

void
fe_set_nonchannel (struct session *sess, int state)
{
	int i;

	if (sess->gui->flag_wid[0])
	{
		for (i = 0; i < 8; i++)
		{
			gtk_widget_set_sensitive (sess->gui->flag_wid[i], state);
		}
		gtk_widget_set_sensitive (sess->gui->limit_entry, state);
		gtk_widget_set_sensitive (sess->gui->key_entry, state);
	}
	if (prefs.inputgad_superfocus)	/* sanity */
		gtk_entry_set_editable ((GtkEntry *) sess->gui->topicgad, FALSE);
	else
		gtk_entry_set_editable ((GtkEntry *) sess->gui->topicgad, state);
}

static void
maingui_createbuttons (session * sess)
{
	struct popup *pop;
	GSList *list = button_list;
	int a = 0, b = 0;

	sess->gui->button_box = gtk_table_new (5, 2, FALSE);
	gtk_box_pack_end (GTK_BOX (sess->gui->nl_box), sess->gui->button_box,
							FALSE, FALSE, 1);
	gtk_widget_show (sess->gui->button_box);

	while (list)
	{
		pop = (struct popup *) list->data;
		if (pop->cmd[0])
		{
			userlist_button (sess->gui->button_box, pop->name, pop->cmd, sess, a,
								  a + 1, b, b + 1);
			a++;
			if (a == 2)
			{
				a = 0;
				b++;
			}
		}
		list = list->next;
	}
}

void
fe_buttons_update (struct session *sess)
{
	if (sess->gui->button_box)
	{
		gtk_widget_destroy (sess->gui->button_box);
		sess->gui->button_box = 0;
	}
	if (!prefs.nouserlistbuttons)
		maingui_createbuttons (sess);
}

void
fe_set_title (struct session *sess)
{
	char tbuf[200];
	char buf[11];					  /* sess->limit, max 10 (2147483647) */
	int i;

	if (!sess->server->connected && !sess->is_dialog)
		strcpy (tbuf, "X-Chat [" VERSION "]");
	else
	{
		if (sess->channel[0] == 0 || sess->is_server)
			snprintf (tbuf, sizeof (tbuf), "X-Chat [" VERSION "]: %s @ %s",
						 sess->server->nick, sess->server->servername);
		else
		{
			snprintf (tbuf,
						 sizeof (tbuf) - sizeof (chan_flags) - 4 - sizeof (buf) -
						 strlen (sess->channelkey),
						 "X-Chat [" VERSION "]: %s @ %s / %s (+",
						 sess->server->nick, sess->server->servername,
						 sess->channel);
			for (i = 0; i < sizeof (chan_flags); i++)
			{
				if (sess->channelflags & (1 << i))
				{
					sprintf (buf, "%c", chan_flags[i]);
					strcat (tbuf, buf);
					if (chan_flags[i] == 'l')
					{
						strcat (tbuf, " ");
						snprintf (buf, sizeof (buf), "%d", sess->limit);
						strcat (tbuf, buf);
						strcat (tbuf, " ");
					}
					if (chan_flags[i] == 'k')
					{
						strcat (tbuf, " ");
						strcat (tbuf, sess->channelkey);
					}
				}
			}
			strcat (tbuf, ")");
		}
	}
	if (sess->is_tab)
	{
		if (!main_window)
			return;
		if (current_tab == sess)
			gtk_window_set_title ((GtkWindow *) main_window, tbuf);
	} else
		gtk_window_set_title ((GtkWindow *) sess->gui->window, tbuf);
}

void
fe_set_channel (struct session *sess)
{
	if (!sess->is_tab && sess->is_dialog)
		return;
	gtk_label_set_text (GTK_LABEL (sess->gui->changad), sess->channel);
#ifdef USE_PANEL
	if (sess->gui->panel_button)
		gtk_label_set_text (GTK_LABEL
								  (GTK_BIN (sess->gui->panel_button)->child),
								  sess->channel);
#endif
	if (prefs.treeview)
		tree_update ();
}

void
fe_clear_channel (struct session *sess)
{
	gtk_entry_set_text (GTK_ENTRY (sess->gui->topicgad), "");
	gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), " ");
	gtk_label_set_text (GTK_LABEL (sess->gui->changad), "<none>");
#ifdef USE_PANEL
	if (sess->gui->panel_button)
		gtk_label_set_text (GTK_LABEL
								  (GTK_BIN (sess->gui->panel_button)->child),
								  "<none>");
#endif
	clear_user_list (sess);
	if (sess->gui->flag_wid[0])
	{
		int i;
		for (i = 0; i < 8; i++)
			my_gtk_toggle_state (sess->gui->flag_wid[i], FALSE, chan_flags[i],
										sess);
		my_gtk_entry_set_text (sess->gui->limit_entry, "", sess);
		my_gtk_entry_set_text (sess->gui->key_entry, "", sess);
	}
	if (sess->gui->op_xpm)
		gtk_widget_destroy (sess->gui->op_xpm);
	sess->gui->op_xpm = 0;
	if (prefs.treeview)
		tree_update ();
}

void
fe_set_nick (struct server *serv, char *newnick)
{
	GSList *list = sess_list;
	struct session *sess;

	strcpy (serv->nick, newnick);
	if (prefs.nickgad)
	{
		while (list)
		{
			sess = (struct session *) list->data;
			if (sess->server == serv && !sess->is_dialog)
				gtk_label_set_text (GTK_LABEL (sess->gui->nickgad), newnick);
			list = list->next;
		}
	}
}

static void
handle_topicgad (GtkWidget * igad, struct session *sess)
{
	char *topic = gtk_entry_get_text (GTK_ENTRY (igad));
	if (sess->channel[0] && sess->server->connected)
	{
		char *fmt = "TOPIC %s :%s\r\n";
		char *tbuf;
		int len = strlen (fmt) - 3 + strlen (sess->channel) + strlen (topic);
		tbuf = malloc (len);
		snprintf (tbuf, len, "TOPIC %s :%s\r\n", sess->channel, topic);
		tcp_send (sess->server, tbuf);
		free (tbuf);
	} else
		gtk_entry_set_text (GTK_ENTRY (igad), "");
	/* restore focus to the input widget, where the next input will most
likely be */
	gtk_widget_grab_focus (sess->gui->inputgad);
}

static char *
find_selected_nick (struct session *sess)
{
	int row;
	struct User *user;

	row = gtkutil_clist_selection (sess->gui->namelistgad);
	if (row == -1)
		return 0;

	user = gtk_clist_get_row_data (GTK_CLIST (sess->gui->namelistgad), row);
	if (!user)
		return 0;
	return user->nick;
}

static void
ul_button_rel (GtkWidget * widget, GdkEventButton * even,
					struct session *sess)
{
	char *nick;
	int row, col;
	char buf[67];

	if (!even)
		return;
	if (even->button == 3)
	{
		if (gtk_clist_get_selection_info
			 (GTK_CLIST (widget), even->x, even->y, &row, &col) < 0)
			return;
		gtk_clist_unselect_all (GTK_CLIST (widget));
		gtk_clist_select_row (GTK_CLIST (widget), row, 0);
		nick = find_selected_nick (sess);
		if (nick)
		{
			menu_nickmenu (sess, even, nick);
		}
		return;
	}
	if (even->button == 2)
	{
		if (gtk_clist_get_selection_info
			 (GTK_CLIST (widget), even->x, even->y, &row, &col) != -1)
		{
			gtk_clist_select_row (GTK_CLIST (widget), row, col);
			nick = find_selected_nick (sess);
			if (nick)
			{
				snprintf (buf, sizeof (buf), "%s: ", nick);
				gtk_entry_set_text (GTK_ENTRY (sess->gui->inputgad), buf);
				gtk_widget_grab_focus (sess->gui->inputgad);
			}
		}
	}
}

void
add_tip (GtkWidget * wid, char *text)
{
	GtkTooltips *tip = gtk_tooltips_new ();
	gtk_tooltips_set_tip (tip, wid, text, 0);
}

void
focus_in (GtkWindow * win, GtkWidget * wid, struct session *sess)
{
	if (!sess)
	{
		if (current_tab)
		{
			if (!current_tab->is_shell)
				gtk_widget_grab_focus (current_tab->gui->inputgad);
			else
				gtk_widget_grab_focus (current_tab->gui->textgad);
			menu_sess = current_tab;
			if (!prefs.use_server_tab)
				current_tab->server->front_session = current_tab;
		}
	} else
	{
		if (!prefs.use_server_tab)
			sess->server->front_session = sess;
		if (!sess->is_shell)
			gtk_widget_grab_focus (sess->gui->inputgad);
		else
			gtk_widget_grab_focus (sess->gui->textgad);
		menu_sess = sess;
#ifdef USE_PANEL
		if (sess->gui->panel_button)
			gtk_widget_set_style (GTK_BIN (sess->gui->panel_button)->child,
										 normaltab_style);
#endif
		if (prefs.treeview)
			tree_default_style (sess);
	}
}

static int
check_is_number (char *t)
{
	int len = strlen (t), c;

	for (c = 0; c < len; c++)
	{
		if (t[c] < '0' || t[c] > '9')
			return FALSE;
	}
	return TRUE;
}

static void
change_channel_flag (GtkWidget * wid, struct session *sess, char flag)
{
	if (sess->server->connected && sess->channel[0])
	{
		char outbuf[512];
		if (GTK_TOGGLE_BUTTON (wid)->active)
			sprintf (outbuf, "MODE %s +%c\r\n", sess->channel, flag);
		else
			sprintf (outbuf, "MODE %s -%c\r\n", sess->channel, flag);
		tcp_send (sess->server, outbuf);
		sprintf (outbuf, "MODE %s\r\n", sess->channel);
		tcp_send (sess->server, outbuf);
		sess->ignore_mode = TRUE;
		sess->ignore_date = TRUE;
	}
}

static void
flagt_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 't');
}

static void
flagn_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 'n');
}

static void
flags_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 's');
}

static void
flagi_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 'i');
}

static void
flagp_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 'p');
}

static void
flagm_hit (GtkWidget * wid, struct session *sess)
{
	change_channel_flag (wid, sess, 'm');
}

static void
flagl_hit (GtkWidget * wid, struct session *sess)
{
	if (GTK_TOGGLE_BUTTON (wid)->active)
	{
		if (sess->server->connected && sess->channel[0])
		{
			char outbuf[512];
			if (check_is_number
				 (gtk_entry_get_text (GTK_ENTRY (sess->gui->limit_entry))) ==
				 FALSE)
			{
				gtkutil_simpledialog ("User limit must be a number!\n");
				gtk_entry_set_text (GTK_ENTRY (sess->gui->limit_entry), "");
				gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (wid), FALSE);
				return;
			}
			sprintf (outbuf, "MODE %s +l %d\r\n", sess->channel,
						atoi (gtk_entry_get_text
								(GTK_ENTRY (sess->gui->limit_entry))));
			tcp_send (sess->server, outbuf);
			sprintf (outbuf, "MODE %s\r\n", sess->channel);
			tcp_send (sess->server, outbuf);
		}
	} else
		change_channel_flag (wid, sess, 'l');
}

static void
flagk_hit (GtkWidget * wid, struct session *sess)
{
	char outbuf[512];

	if (GTK_TOGGLE_BUTTON (wid)->active)
	{
		if (sess->server->connected && sess->channel[0])
		{
			snprintf (outbuf, 512, "MODE %s +k %s\r\n", sess->channel,
						 gtk_entry_get_text (GTK_ENTRY (sess->gui->key_entry)));
			tcp_send (sess->server, outbuf);
			snprintf (outbuf, 512, "MODE %s\r\n", sess->channel);
			tcp_send (sess->server, outbuf);
		}
	} else
	{
		if (sess->server->connected && sess->channel[0])
		{
			snprintf (outbuf, 512, "MODE %s -k %s\r\n", sess->channel,
						 gtk_entry_get_text (GTK_ENTRY (sess->gui->key_entry)));
			tcp_send (sess->server, outbuf);
			snprintf (outbuf, 512, "MODE %s\r\n", sess->channel);
			tcp_send (sess->server, outbuf);
		}
	}
}

static void
key_entry (GtkWidget * igad, struct session *sess)
{
	if (sess->server->connected && sess->channel[0])
	{
		char outbuf[512];
		sprintf (outbuf, "MODE %s +k %s\r\n", sess->channel,
					gtk_entry_get_text (GTK_ENTRY (igad)));
		tcp_send (sess->server, outbuf);
		sprintf (outbuf, "MODE %s\r\n", sess->channel);
		tcp_send (sess->server, outbuf);
	}
}

static void
limit_entry (GtkWidget * igad, struct session *sess)
{
	char outbuf[512];
	if (sess->server->connected && sess->channel[0])
	{
		if (check_is_number (gtk_entry_get_text (GTK_ENTRY (igad))) == FALSE)
		{
			gtk_entry_set_text (GTK_ENTRY (igad), "");
			gtkutil_simpledialog ("User limit must be a number!\n");
			gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (sess->gui->flag_l),
												  FALSE);
			return;
		}
		sprintf (outbuf, "MODE %s +l %d\r\n", sess->channel,
					atoi (gtk_entry_get_text (GTK_ENTRY (igad))));
		tcp_send (sess->server, outbuf);
		sprintf (outbuf, "MODE %s\r\n", sess->channel);
		tcp_send (sess->server, outbuf);
	}
}

void
show_and_unfocus (GtkWidget * wid)
{
	GTK_WIDGET_UNSET_FLAGS (wid, GTK_CAN_FOCUS);
	gtk_widget_show (wid);
}

static void
add_flag_wid (GtkWidget ** wid, char *tip, GtkWidget * box, char *face,
				  void *callback, gpointer userdata)
{
	*wid = gtk_toggle_button_new_with_label (face);
	gtk_widget_set_usize (*wid, 18, -1);
	add_tip (*wid, tip);
	gtk_box_pack_end (GTK_BOX (box), *wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (*wid), "toggled",
							  GTK_SIGNAL_FUNC (callback), userdata);
	show_and_unfocus (*wid);
}

static void
userlist_button (GtkWidget * box, char *label, char *cmd,
					  struct session *sess, int a, int b, int c, int d)
{
	GtkWidget *wid = gtk_button_new_with_label (label);
	gtk_object_set_user_data (GTK_OBJECT (wid), sess);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (userlist_button_cb), cmd);
	gtk_table_attach_defaults (GTK_TABLE (box), wid, a, b, c, d);
	show_and_unfocus (wid);
}

int
textgad_get_focus_cb (GtkWidget * wid, GdkEventKey * event,
							 struct session *sess)
{
	char text[2] = " ";

	if (event->keyval >= GDK_space && event->keyval <= GDK_asciitilde)
	{
		text[0] = event->keyval;
		gtk_entry_append_text (GTK_ENTRY (sess->gui->inputgad), text);
		gtk_widget_grab_focus (sess->gui->inputgad);
		return FALSE;
	} else if (event->keyval == GDK_BackSpace)
	{
		gtk_widget_grab_focus (sess->gui->inputgad);
		return FALSE;
	}
	return TRUE;
}

#define WORD_URL     1
#define WORD_NICK    2
#define WORD_CHANNEL 3
#define WORD_HOST    4
#define WORD_EMAIL   5
#define WORD_DIALOG  -1

/* check if a word is clickable */

int
maingui_word_check (GtkXText * xtext, char *word)
{
	session *sess;
	char *at, *dot;
	int i, dots;
	int len = strlen (word);

	if ((word[0] == '@' || word[0] == '+') && word[1] == '#')
		return WORD_CHANNEL;

	if (word[0] == '#' && word[1] != '#' && word[1] != 0)
		return WORD_CHANNEL;

	if (!strncasecmp (word, "irc://", 6))
		return WORD_URL;

	if (!strncasecmp (word, "irc.", 4))
		return WORD_URL;

	if (!strncasecmp (word, "ftp.", 4))
		return WORD_URL;

	if (!strncasecmp (word, "ftp:", 4))
		return WORD_URL;

	if (!strncasecmp (word, "www.", 4))
		return WORD_URL;

	if (!strncasecmp (word, "http:", 5))
		return WORD_URL;

	if (!strncasecmp (word, "https:", 6))
		return WORD_URL;

	sess = gtk_object_get_user_data (GTK_OBJECT (xtext));

	if (find_name (sess, word))
		return WORD_NICK;

	at = strchr (word, '@');	  /* check for email addy */
	dot = strrchr (word, '.');
	if (at && dot)
	{
		if ((unsigned long) at < (unsigned long) dot)
		{
			if (strchr (word, '*'))
				return WORD_HOST;
			else
				return WORD_EMAIL;
		}
	}

	/* check if it's an IP number */
	dots = 0;
	for (i = 0; i < len; i++)
	{
		if (word[i] == '.')
			dots++;
	}
	if (dots == 3)
	{
		if (inet_addr (word) != -1)
			return WORD_HOST;
	}

	if (!strncasecmp (word + len - 5, ".html", 5))
		return WORD_HOST;

	if (!strncasecmp (word + len - 4, ".org", 4))
		return WORD_HOST;

	if (!strncasecmp (word + len - 4, ".net", 4))
		return WORD_HOST;

	if (!strncasecmp (word + len - 4, ".com", 4))
		return WORD_HOST;

	if (!strncasecmp (word + len - 4, ".edu", 4))
		return WORD_HOST;

	if (len > 5)
	{
		if (word[len - 3] == '.' &&
			 isalpha (word[len - 2]) && isalpha (word[len - 1]))
			return WORD_HOST;
	}

	if (sess->is_dialog)
		return WORD_DIALOG;

	return 0;
}

/* mouse click inside text area */

void
maingui_word_clicked (GtkXText *xtext, char *word, GdkEventButton *even,
							 session *sess)
{

	if (even->button == 1)			/* left button */
	{
		if (even->state & GDK_CONTROL_MASK)
		{
			switch (maingui_word_check (xtext, word))
			{
			case WORD_URL:
			case WORD_HOST:
				goto_url (0, word);
			}
		}
		return;
	}

	if (even->button == 2)
	{
		if (sess->is_dialog)
			menu_middlemenu (sess, even);
		return;
	}

	switch (maingui_word_check (xtext, word))
	{
	case 0:
		menu_middlemenu (sess, even);
		break;
	case WORD_URL:
	case WORD_HOST:
		menu_urlmenu (sess, even, word);
		break;
	case WORD_NICK:
		menu_nickmenu (sess, even, word);
		break;
	case WORD_CHANNEL:
		if (*word == '@' || *word == '+')
			word++;
		menu_chanmenu (sess, even, word);
		break;
	case WORD_EMAIL:
		{
			char *newword = malloc (strlen (word) + 10);
			if (*word == '~')
				word++;
			sprintf (newword, "mailto:%s", word);
			menu_urlmenu (sess, even, newword);
			free (newword);
		}
		break;
	case WORD_DIALOG:
		menu_nickmenu (sess, even, sess->channel);
		break;
	}
}

void
maingui_configure (GtkWidget * unused)
{
	if (menu_sess)
	{
		if (!menu_sess->is_shell)
		{
			if (((GtkXText *) menu_sess->gui->textgad)->transparent)
			{
				gtk_widget_queue_draw (menu_sess->gui->textgad);
			}
		}
	}
}

static void
maingui_create_textlist (struct session *sess, GtkWidget * leftpane)
{
	sess->gui->textgad =
		gtk_xtext_new (prefs.indent_pixels * prefs.indent_nicks,
							prefs.show_separator);

	gtk_object_set_user_data (GTK_OBJECT (sess->gui->textgad), sess);

	((GtkXText *) sess->gui->textgad)->double_buffer = prefs.double_buffer;
	((GtkXText *) sess->gui->textgad)->wordwrap = prefs.wordwrap;
	((GtkXText *) sess->gui->textgad)->max_auto_indent = prefs.max_auto_indent;
	((GtkXText *) sess->gui->textgad)->auto_indent = prefs.auto_indent;
	((GtkXText *) sess->gui->textgad)->thinline = prefs.thin_separator;
	((GtkXText *) sess->gui->textgad)->max_lines = prefs.max_lines;
	((GtkXText *) sess->gui->textgad)->error_function = gtkutil_simpledialog;
	((GtkXText *) sess->gui->textgad)->urlcheck_function = maingui_word_check;

	((GtkXText *) sess->gui->textgad)->tint_red = prefs.tint_red;
	((GtkXText *) sess->gui->textgad)->tint_green = prefs.tint_green;
	((GtkXText *) sess->gui->textgad)->tint_blue = prefs.tint_blue;

	if (prefs.timestamp && prefs.indent_nicks)
		((GtkXText *) sess->gui->textgad)->time_stamp = TRUE;

	gtk_xtext_set_palette (GTK_XTEXT (sess->gui->textgad), colors);
	gtk_xtext_set_font (GTK_XTEXT (sess->gui->textgad), font_normal, 0);
	gtk_xtext_set_background (GTK_XTEXT (sess->gui->textgad),
									  channelwin_pix, prefs.transparent, prefs.tint);

	gtk_widget_set_usize (sess->gui->textgad,
								 prefs.mainwindow_width - 115,
								 prefs.mainwindow_height - 105);
	gtk_container_add (GTK_CONTAINER (leftpane), sess->gui->textgad);
	show_and_unfocus (sess->gui->textgad);

	sess->gui->vscrollbar =
		gtk_vscrollbar_new (GTK_XTEXT (sess->gui->textgad)->adj);
	gtk_box_pack_start (GTK_BOX (leftpane), sess->gui->vscrollbar, FALSE,
							  FALSE, 1);
	show_and_unfocus (sess->gui->vscrollbar);

	if (!sess->is_tab)
		gtk_signal_connect_object (GTK_OBJECT (sess->gui->window),
											"configure_event",
											GTK_SIGNAL_FUNC (maingui_configure),
											GTK_OBJECT (sess->gui->textgad));

	gtk_signal_connect (GTK_OBJECT (sess->gui->textgad), "word_click",
							  GTK_SIGNAL_FUNC (maingui_word_clicked), sess);
}

static void
gui_new_tab (session * sess)
{
	current_tab = sess;
	menu_sess = sess;
	if (!prefs.use_server_tab)
		sess->server->front_session = sess;
	fe_set_title (sess);
	if (!sess->is_shell)
		gtk_widget_grab_focus (sess->gui->inputgad);

#ifdef USE_PANEL
	if (sess->gui->panel_button)
		gtk_widget_set_style (GTK_BIN (sess->gui->panel_button)->child,
									 normaltab_style);
#endif
	if (sess->new_data || sess->nick_said)
	{
		sess->nick_said = FALSE;
		sess->new_data = FALSE;
		gtk_widget_set_rc_style (sess->gui->changad);
		/*gtk_widget_set_style (sess->gui->changad, normaltab_style); */
	}
}

static void
gui_new_tab_callback (GtkWidget * widget, GtkNotebookPage * nbpage,
							 guint page)
{
	struct session *sess;
	GSList *list = sess_list;

	if (xchat_is_quitting)
		return;

	while (list)
	{
		sess = (struct session *) list->data;
		if (sess->gui->window == nbpage->child)
		{
			gui_new_tab (sess);
			if (main_window)
				gtk_widget_set_sensitive (main_menu, TRUE);
			return;
		}
		list = list->next;
	}
	/* we're moved to a tab that isn't a session, the menus would crash! */
	if (main_window)
		gtk_widget_set_sensitive (main_menu, FALSE);
	current_tab = 0;
	menu_sess = 0;
}

int
maingui_pagetofront (int page)
{
	gtk_notebook_set_page (GTK_NOTEBOOK (main_book), page);
	return 0;
}

static void
gui_mainbook_invalid (GtkWidget * w, GtkWidget * main_window)
{
	main_book = NULL;
	gtk_widget_destroy (main_window);
}

static void
gui_main_window_kill (GtkWidget * win, struct session *sess)
{
	GSList *list;

	xchat_is_quitting = TRUE;

	/* see if there's any non-tab windows left */
	list = sess_list;
	while (list)
	{
		sess = (session *) list->data;
		if (!sess->is_tab)
		{
			xchat_is_quitting = FALSE;
			break;
		}
		list = list->next;
	}

	main_window = 0;
	current_tab = 0;
}

void
userlist_hide (GtkWidget *igad, struct session *sess)
{
#ifdef USE_GNOMEE
	if (sess->userlisthidden > 0)
	{
		if (sess->gui->paned)
			gtk_paned_set_position (GTK_PANED (sess->gui->paned),
											sess->userlisthidden);
		else
			gtk_widget_show (sess->gui->userlistbox);
		sess->userlisthidden = 0;
	} else
	{
		if (sess->gui->paned)
		{
			sess->userlisthidden = GTK_PANED (sess->gui->paned)->handle_xpos + 3;
			gtk_paned_set_position (GTK_PANED (sess->gui->paned), 1200);
		} else
		{
			sess->userlisthidden = 1;
			gtk_widget_hide (sess->gui->userlistbox);
		}
	}
#else
	if (sess->userlisthidden)
	{
		if (igad)
			gtk_label_set (GTK_LABEL (GTK_BIN (igad)->child), ">");
		if (sess->gui->paned)
			gtk_paned_set_position (GTK_PANED (sess->gui->paned),
											sess->userlisthidden);
		else
			gtk_widget_show (sess->gui->userlistbox);
		sess->userlisthidden = FALSE;
		prefs.hideuserlist = 0;
	} else
	{
		if (igad)
			gtk_label_set (GTK_LABEL (GTK_BIN (igad)->child), "<");
		if (sess->gui->paned)
		{
			sess->userlisthidden = GTK_PANED (sess->gui->paned)->handle_xpos + 3;
			gtk_paned_set_position (GTK_PANED (sess->gui->paned), 1200);
		} else
		{
			sess->userlisthidden = TRUE;
			gtk_widget_hide (sess->gui->userlistbox);
		}
		prefs.hideuserlist = 1;
	}
#endif
}

static void
maingui_userlist_selected (GtkWidget * clist, gint row, gint column,
									GdkEventButton * even)
{
	char *nick;
	void *unused;

	if (even)
	{
		if (even->type == GDK_2BUTTON_PRESS)
		{
			if (prefs.doubleclickuser[0])
			{

				if (gtk_clist_get_cell_type (GTK_CLIST (clist), row, column) ==
					 GTK_CELL_PIXTEXT)
				{
					gtk_clist_get_pixtext (GTK_CLIST (clist), row, column, &nick,
												  (guint8 *) & unused,
												  (GdkPixmap **) & unused,
												  (GdkBitmap **) & unused);
				} else
					gtk_clist_get_text (GTK_CLIST (clist), row, column, &nick);
				nick_command_parse (menu_sess, prefs.doubleclickuser, nick, nick);
			}
		} else
		{
			if (!(even->state & GDK_SHIFT_MASK))
			{
				gtk_clist_unselect_all (GTK_CLIST (clist));
				gtk_clist_select_row (GTK_CLIST (clist), row, column);
			}
		}
	}
}

/* Treeview code --AGL */

static GList *tree_list = NULL;

#define TREE_SERVER 0
#define TREE_SESSION 1

struct tree_data
{
	int type;
	void *data;
};

static void
tree_row_destroy (struct tree_data *td)
{
	g_free (td);
}

static void
tree_add_sess (GSList ** o_ret, struct server *serv)
{
	GSList *ret = *o_ret;
	GSList *session;
	struct session *sess;

	session = sess_list;
	while (session)
	{
		sess = session->data;
		if (sess->server == serv && !sess->is_server)
			ret = g_slist_prepend (ret, sess);
		session = session->next;
	}

	*o_ret = ret;
	return;
}

static GSList *
tree_build ()
{
	GSList *serv;
	GSList *ret = NULL;
	struct server *server;

	serv = serv_list;
	while (serv)
	{
		server = serv->data;
		ret = g_slist_prepend (ret, server);
		ret = g_slist_prepend (ret, NULL);
		tree_add_sess (&ret, server);
		ret = g_slist_prepend (ret, NULL);
		serv = serv->next;
	}

	ret = g_slist_reverse (ret);
	return ret;
}

static gpointer
tree_new_entry (int type, void *data)
{
	struct tree_data *td = NULL;

	td = g_new (struct tree_data, 1);
	td->type = type;
	td->data = data;

	return td;
}

static void
tree_populate (GtkCTree * tree, GSList * l)
{
	int state = 0;
	void *data;
	gchar *text[1];
	GtkCTreeNode *parent = NULL, *leaf = NULL;

	gtk_clist_freeze (GTK_CLIST (tree));
	gtk_clist_clear (GTK_CLIST (tree));
	for (; l; l = l->next)
	{
		data = l->data;
		if (data == NULL)
		{
			if (!state)
			{
				state = 1;
				continue;
			} else
			{
				state = 0;
				continue;
			}
		}
		if (!state)
		{
			text[0] = ((struct server *) data)->servername;
			if (text[0][0])
			{
				parent = gtk_ctree_insert_node (tree, NULL, NULL, text, 0, NULL,
														  NULL, NULL, NULL, 0, 1);
				((GtkCListRow *) ((GList *) parent)->data)->data =
					tree_new_entry (TREE_SERVER, data);
				((GtkCListRow *) ((GList *) parent)->data)->destroy =
					(GtkDestroyNotify) tree_row_destroy;
			}
			continue;
		} else
		{
			text[0] = ((struct session *) data)->channel;
			if (text[0][0])
			{
				leaf = gtk_ctree_insert_node (tree, parent, NULL, text, 0, NULL,
														NULL, NULL, NULL, 1, 1);
				((GtkCListRow *) ((GList *) leaf)->data)->data =
					tree_new_entry (TREE_SESSION, data);
				((GtkCListRow *) ((GList *) leaf)->data)->destroy =
					(GtkDestroyNotify) tree_row_destroy;
			}
			continue;
		}
	}
	gtk_clist_thaw (GTK_CLIST (tree));
}

static void
tree_destroy (GtkWidget * tree)
{
	tree_list = g_list_remove (tree_list, tree);
}

static void
tree_select_row (GtkWidget * tree, GList * row)
{
	struct tree_data *td;
	struct session *sess = NULL;
	struct server *serv = NULL;
	int page;

	td = ((struct tree_data *) ((GtkCListRow *) row->data)->data);
	if (!td)
		return;
	if (td->type == TREE_SESSION)
	{
		sess = td->data;
		if (sess->is_tab)
		{
			if (main_window)		  /* this fixes a little refresh glitch */
			{
				page = gtk_notebook_page_num (GTK_NOTEBOOK (main_book),
														sess->gui->window);
				maingui_pagetofront (page);
			}
		} else
		{
			gtk_widget_hide (sess->gui->window);
			gtk_widget_show (sess->gui->window);
		}
		return;
	} else if (td->type == TREE_SERVER)
	{
		serv = td->data;
		sess = serv->front_session;
		if (serv->front_session)
		{
			if (serv->front_session->is_tab)
			{
				if (main_window)
				{
					page = gtk_notebook_page_num (GTK_NOTEBOOK (main_book),
															sess->gui->window);
					maingui_pagetofront (page);
				}
			} else
			{
				gtk_widget_hide (sess->gui->window);
				gtk_widget_show (sess->gui->window);
			}
		}
		return;
	}
}

static GtkWidget *
new_tree_view ()
{
	GtkWidget *tree;
	GSList *data;

	tree = gtk_ctree_new_with_titles (1, 0, NULL);
	gtk_clist_set_selection_mode (GTK_CLIST (tree), GTK_SELECTION_BROWSE);
	gtk_clist_set_column_width (GTK_CLIST (tree), 0, 80);
	gtk_signal_connect (GTK_OBJECT (tree), "destroy", tree_destroy, NULL);
	gtk_signal_connect (GTK_OBJECT (tree), "tree_select_row", tree_select_row,
							  0);
	data = tree_build ();
	tree_populate (GTK_CTREE (tree), data);
	tree_list = g_list_prepend (tree_list, tree);
	g_slist_free (data);

	return tree;
}

void
tree_update ()
{
	GList *tree;
	GSList *data = tree_build ();

	for (tree = tree_list; tree; tree = tree->next)
		tree_populate (GTK_CTREE (tree->data), data);

	g_slist_free (data);
}

void
tree_default_style (struct session *sess)
{
	GList *tree;
	GList *rows;
	int row = -1;

	for (tree = tree_list; tree; tree = tree->next)
	{
		if (row > -1)
			gtk_clist_set_foreground (GTK_CLIST (tree->data), row, &colors[1]);
		row = 0;
		for (rows = (GTK_CLIST (tree->data)->row_list); rows; rows = rows->next)
		{
			if (((GtkCListRow *) rows->data)->data == sess)
			{
				gtk_clist_set_foreground (GTK_CLIST (tree->data), row,
												  &colors[1]);
				continue;
			}
			row++;
		}
	}
}

void
tree_red_style (struct session *sess)
{
	GList *tree;
	GList *rows;
	int row = -1;

	for (tree = tree_list; tree; tree = tree->next)
	{
		if (row > -1)
			gtk_clist_set_foreground (GTK_CLIST (tree->data), row, &colors[4]);
		row = 0;
		for (rows = (GTK_CLIST (tree->data)->row_list); rows; rows = rows->next)
		{
			if (((GtkCListRow *) rows->data)->data == sess)
			{
				gtk_clist_set_foreground (GTK_CLIST (tree->data), row,
												  &colors[4]);
				continue;
			}
			row++;
		}
	}
}

void
tree_blue_style (struct session *sess)
{
	GList *tree;
	GList *rows;
	int row = -1;

	for (tree = tree_list; tree; tree = tree->next)
	{
		if (row > -1)
			gtk_clist_set_foreground (GTK_CLIST (tree->data), row, &colors[2]);
		row = 0;
		for (rows = (GTK_CLIST (tree->data)->row_list); rows; rows = rows->next)
		{
			if (((GtkCListRow *) rows->data)->data == sess)
			{
				gtk_clist_set_foreground (GTK_CLIST (tree->data), row,
												  &colors[2]);
				continue;
			}
			row++;
		}
	}
}

void
maingui_set_tab_pos (int pos)
{
	gtk_notebook_set_show_tabs ((GtkNotebook *) main_book, TRUE);
	switch (pos)
	{
	case 0:
		gtk_notebook_set_tab_pos ((GtkNotebook *) main_book, GTK_POS_BOTTOM);
		break;
	case 1:
		gtk_notebook_set_tab_pos ((GtkNotebook *) main_book, GTK_POS_TOP);
		break;
	case 2:
		gtk_notebook_set_tab_pos ((GtkNotebook *) main_book, GTK_POS_LEFT);
		break;
	case 3:
		gtk_notebook_set_tab_pos ((GtkNotebook *) main_book, GTK_POS_RIGHT);
		break;
	case 4:
		gtk_notebook_set_show_tabs ((GtkNotebook *) main_book, FALSE);
		break;
	}
}

static void
gui_make_tab_window (struct session *sess)
{
	GtkWidget *main_box, *main_hbox = NULL, *trees;
#ifndef USE_GNOME
	GtkWidget *wid;
#endif

	if (!main_window)
	{
		current_tab = 0;
#ifdef USE_GNOME
		main_window = gnome_app_new ("X-Chat", "X-Chat");
#else
		main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
#endif

		gtk_widget_realize (main_window);
		maingui_set_icon (main_window);
		gtk_signal_connect ((GtkObject *) main_window, "destroy",
								  GTK_SIGNAL_FUNC (gui_main_window_kill), sess);
		gtk_signal_connect ((GtkObject *) main_window, "focus_in_event",
								  GTK_SIGNAL_FUNC (focus_in), 0);
		gtk_signal_connect_object (GTK_OBJECT (main_window), "configure_event",
											GTK_SIGNAL_FUNC (maingui_configure), 0);
		gtk_window_set_policy ((GtkWindow *) main_window, TRUE, TRUE, FALSE);

		main_box = gtk_vbox_new (0, 0);
#ifdef USE_GNOME
		gnome_app_set_contents (GNOME_APP (main_window), main_box);
#else
		gtk_container_add (GTK_CONTAINER (main_window), main_box);
#endif
		gtk_widget_show (main_box);

#ifdef USE_GNOME
		main_menu = createmenus (main_window, sess, 1);
		main_menu_bar = main_menu->parent;
#else
		main_menu = createmenus (0, sess, 1);
		gtk_widget_show (main_menu);

		main_menu_bar = wid = gtk_handle_box_new ();
		gtk_container_add (GTK_CONTAINER (wid), main_menu);
		gtk_box_pack_start (GTK_BOX (main_box), wid, FALSE, TRUE, 0);
		gtk_widget_show (wid);
#endif
		if (prefs.treeview)
		{
			main_hbox = gtk_hpaned_new ();
			trees = new_tree_view ();
			gtk_widget_show (trees);
			gtk_paned_add1 (GTK_PANED (main_hbox), trees);
		}

		main_book = gtk_notebook_new ();
		gtk_notebook_set_show_border (GTK_NOTEBOOK (main_book), FALSE);
		maingui_set_tab_pos (prefs.tabs_position);
		gtk_notebook_set_scrollable ((GtkNotebook *) main_book, TRUE);
		gtk_signal_connect ((GtkObject *) main_book, "switch_page",
								  GTK_SIGNAL_FUNC (gui_new_tab_callback), 0);
		gtk_signal_connect ((GtkObject *) main_book, "destroy",
								  GTK_SIGNAL_FUNC (gui_mainbook_invalid),
								  main_window);
		if (prefs.treeview)
		{
			gtk_container_add (GTK_CONTAINER (main_box), main_hbox);
			gtk_paned_add2 (GTK_PANED (main_hbox), main_book);
			gtk_widget_show (main_hbox);
		} else
			gtk_container_add (GTK_CONTAINER (main_box), main_book);

		if (prefs.inputgad_superfocus)
			show_and_unfocus (main_book);
		else
			gtk_widget_show (main_book);
	}
}

static int
maingui_refresh (session * sess)
{
#ifdef USE_ZVT
	if (sess->is_shell)
	{
		menu_newshell_set_palette (sess);
		gtk_widget_queue_draw (sess->gui->textgad);
	} else
#endif
		gtk_xtext_refresh (GTK_XTEXT (sess->gui->textgad), 1);
	return 0;
}

/* This function takes a session and toggles it between a tab and a free window */
int
relink_window (GtkWidget * w, struct session *sess)
{
	GtkWidget *old, *wid;
	int page, num, need = 0;

	if (sess->is_tab)
	{
		/* It is currently a tab so we need to make a window */

		/* Warning! Hack alert!, since we need to destroy the main_book on the last page,
		   I get the current page. If it is 0 (the first page) then I
		   try to get page 1. If that doesn't exist I assume it is the only page.
		   It works with GTK 1.2.0 but GTK could change in the future. WATCH OUT! 
		   -- AGL (9/4/99) */

		num = gtk_notebook_get_current_page (GTK_NOTEBOOK (main_book));
		if (num == 0)
		{
			if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (main_book), 1) == NULL)
				need = TRUE;
		}
		sess->is_tab = 0;
		old = sess->gui->window;
		gtk_signal_disconnect_by_data (GTK_OBJECT (old), sess);
#ifdef USE_GNOME
		sess->gui->window = gnome_app_new ("X-Chat", "X-Chat");
#else
		sess->gui->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
#endif
		gtk_widget_realize (sess->gui->window);
		maingui_set_icon (sess->gui->window);
		if (!sess->is_dialog && !sess->is_shell)
		{
#ifdef USE_GNOME
			sess->gui->menu = createmenus (GNOME_APP (sess->gui->window), sess, 1);
#else
			wid = gtk_handle_box_new ();
			gtk_box_pack_start (GTK_BOX (sess->gui->vbox), wid, FALSE, FALSE, 0);
			gtk_box_reorder_child (GTK_BOX (sess->gui->vbox), wid, 0);
			gtk_widget_show (wid);

			sess->gui->menu = createmenus (0, sess, 1);
			gtk_container_add (GTK_CONTAINER (wid), sess->gui->menu);
			gtk_widget_show (sess->gui->menu);
#endif
		}
		fe_set_title (sess);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "destroy",
								  GTK_SIGNAL_FUNC (gtk_kill_session_callback), sess);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "focus_in_event",
								  GTK_SIGNAL_FUNC (focus_in), sess);
		gtk_window_set_policy ((GtkWindow *) sess->gui->window, TRUE, TRUE,
									  FALSE);
#ifdef USE_GNOME
		wid = gtk_hbox_new (0, 0);
		gtk_widget_reparent (sess->gui->vbox, wid);
		gnome_app_set_contents (GNOME_APP (sess->gui->window), wid);
#else
		gtk_widget_reparent (sess->gui->vbox, sess->gui->window);
#endif
		if (!sess->is_dialog)
		{
			if (sess->channel[0] == 0)
				sess->gui->changad = gtk_label_new ("<none>");
			else
				sess->gui->changad = gtk_label_new (sess->channel);
			gtk_box_pack_start (GTK_BOX (sess->gui->tbox), sess->gui->changad,
									  FALSE, FALSE, 5);
			gtk_box_reorder_child (GTK_BOX (sess->gui->tbox), sess->gui->changad, 4);
			gtk_widget_show (sess->gui->changad);
		} else
			sess->gui->changad = NULL;
		gtk_widget_show_all (sess->gui->window);

#ifdef USE_ZVT
		if (sess->is_shell)
			menu_newshell_set_palette (sess);
		else
#endif
			gtk_xtext_refresh (GTK_XTEXT (sess->gui->textgad), 1);

		if (sess->gui->toolbox)
			gtk_widget_hide (sess->gui->toolbox);
		num = gtk_notebook_page_num (GTK_NOTEBOOK (main_book), old);
		gtk_notebook_remove_page (GTK_NOTEBOOK (main_book), num);
		if (prefs.mainwindow_left || prefs.mainwindow_top)
			gdk_window_move (sess->gui->window->window,
								  prefs.mainwindow_left, prefs.mainwindow_top);
		if (need)
			gtk_widget_destroy (main_book);
		return 0;
	} else
	{
		/* We have a free window so we need to make it a tab */
		if (main_book == NULL)
		{
			/* Oh dear, we don't *have* a main_book, so we need to make one */
			gui_make_tab_window (sess);
			need = TRUE;
		}
		if (sess->gui->menu)
		{
#ifndef USE_GNOME
			/* this will destroy the HandleBox and its children */
			gtk_widget_destroy (sess->gui->menu->parent);
#else
			gtk_widget_destroy (sess->gui->menu);
#endif
			sess->gui->menu = NULL;
		}
		sess->is_tab = 1;
		old = sess->gui->window;
		gtk_signal_disconnect_by_data (GTK_OBJECT (old), sess);
		sess->gui->window = gtk_hbox_new (0, 0);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "destroy",
								  GTK_SIGNAL_FUNC (gtk_kill_session_callback), sess);
		gtk_widget_reparent (sess->gui->vbox, sess->gui->window);
		gtk_widget_destroy (old);

		/* FIXME: Erm, I think gtk_notebook_remove_page will destroy the changad,
		   if not then we have a memory leak. Could someoue check this?
		   -- AGL (9/4/99) */

		if (sess->gui->changad != NULL)
			gtk_widget_destroy (sess->gui->changad);
		if (sess->channel[0] == 0)
			sess->gui->changad = gtk_label_new ("<none>");
		else
			sess->gui->changad = gtk_label_new (sess->channel);

		gtk_widget_show (sess->gui->changad);
		gtk_notebook_append_page (GTK_NOTEBOOK (main_book), sess->gui->window,
										  sess->gui->changad);
		gtk_widget_show_all (sess->gui->window);
		if (need)
			gtk_widget_show_all (main_window);
		if (sess->gui->toolbox)
			gtk_widget_hide (sess->gui->toolbox);
		page =
			gtk_notebook_page_num (GTK_NOTEBOOK (main_book), sess->gui->window);
		maingui_pagetofront (page);
		gtk_idle_add ((GtkFunction) maingui_refresh, (gpointer) sess);

		/* dialog windows don't have this box */
		if (sess->gui->userlistbox && !sess->is_dialog)
		{
			gtk_widget_realize (sess->gui->userlistbox);
			gdk_window_set_background (sess->gui->userlistbox->window,
												&sess->gui->userlistbox->
												style->bg[GTK_STATE_NORMAL]);
			gdk_window_set_back_pixmap (main_book->window, 0, 0);
		}

		return 0;
	}
}

#ifdef USE_GNOME
GtkTargetEntry dnd_targets[] = {
	{"text/uri-list", 0, 1}
};
#endif

/* 'X' button pressed */

void
X_session (GtkWidget * button, struct session *sess)
{
/*   GtkWidget *mbox;

   if (!sess_list->next)
   {
	   mbox = gnome_message_box_new ("DCCs still active, quit?",
				                     GNOME_MESSAGE_BOX_QUESTION,
                                 GNOME_STOCK_BUTTON_YES,
                                 GNOME_STOCK_BUTTON_CANCEL, NULL);
      gtk_widget_show (mbox);
   } else*/
	gtk_widget_destroy (sess->gui->window);
}

static void
maingui_init_styles (GtkStyle *style)
{
	normaltab_style = gtk_style_new ();
	gdk_font_unref (normaltab_style->font);
	gdk_font_ref (style->font);
	normaltab_style->font = style->font;

	redtab_style = gtk_style_new ();
	gdk_font_unref (redtab_style->font);
	redtab_style->font = style->font;
	redtab_style->fg[0] = colors[4];

	bluetab_style = gtk_style_new ();
	gdk_font_unref (bluetab_style->font);
	bluetab_style->font = style->font;
	bluetab_style->fg[0] = colors[12];
}

void
maingui_moveleft (GtkWidget * wid)
{
	int pos;
	if (main_window)
	{
		pos = gtk_notebook_get_current_page ((GtkNotebook *) main_book);
		if (pos)
			gtk_notebook_reorder_child ((GtkNotebook *) main_book,
												 gtk_notebook_get_nth_page (
																					 (GtkNotebook
																					  *) main_book,
																					 pos),
												 pos - 1);
	}
}

void
maingui_moveright (GtkWidget * wid)
{
	int pos;
	if (main_window)
	{
		pos = gtk_notebook_get_current_page ((GtkNotebook *) main_book);
		gtk_notebook_reorder_child ((GtkNotebook *) main_book,
											 gtk_notebook_get_nth_page ((GtkNotebook *)
																				 main_book, pos),
											 pos + 1);
	}
}

static void
maingui_toolbox (GtkWidget * button, GtkWidget * box)
{
	if (GTK_WIDGET_VISIBLE (box))
	{
		gtk_label_set_text (GTK_LABEL (GTK_BIN (button)->child), "<");
		gtk_widget_hide (box);
		add_tip (button, "Open Toolbox");
	} else
	{
		gtk_label_set_text (GTK_LABEL (GTK_BIN (button)->child), ">");
		gtk_widget_show (box);
		add_tip (button, "Close Toolbox");
	}
}

static void
maingui_code (GtkWidget * button, char *code)
{
	if (menu_sess)
		key_action_insert (menu_sess->gui->inputgad, 0, code, 0, menu_sess);
}

static GtkWidget *
toolbox_button (char *label, char *code, GtkWidget * box, char *tip)
{
	GtkWidget *wid;

	wid = gtk_button_new_with_label (label);
	gtk_box_pack_end (GTK_BOX (box), wid, 0, 0, 0);
	if (code)
		gtk_signal_connect (GTK_OBJECT (wid), "clicked",
								  GTK_SIGNAL_FUNC (maingui_code), code);
	gtk_widget_show (wid);
	if (tip)
		add_tip (wid, tip);

	return wid;
}

static void
maingui_cp (GtkWidget * button, session * sess)
{
	GTK_XTEXT (sess->gui->textgad)->color_paste =
		GTK_TOGGLE_BUTTON (button)->active;
}

static void
toolbox_color (GtkWidget * button, int color_no)
{
	char buf[8];

	sprintf (buf, "%%C%d", color_no);

	if (menu_sess)
		key_action_insert (menu_sess->gui->inputgad, 0, buf, 0, menu_sess);
}

/* create the < and ^ buttons to the right of the inputbox */

void
gui_create_toolbox (session *sess, GtkWidget *box)
{
	GtkStyle *style;
	GtkWidget *wid, *toolbox;
	int i;

	sess->gui->toolbox = toolbox = gtk_hbox_new (0, 0);
	gtk_box_pack_start (GTK_BOX (box), toolbox, 0, 0, 0);

	sess->gui->confbutton = wid = gtk_toggle_button_new_with_label ("Conf");
	gtk_box_pack_end (GTK_BOX (toolbox), wid, 0, 0, 0);
	gtk_widget_show (wid);
	add_tip (wid, "Conference mode (no join/part msgs)");

	wid = gtk_toggle_button_new_with_label ("CP");
	gtk_signal_connect (GTK_OBJECT (wid), "toggled",
							  GTK_SIGNAL_FUNC (maingui_cp), sess);
	gtk_box_pack_end (GTK_BOX (toolbox), wid, 0, 0, 0);
	gtk_widget_show (wid);
	add_tip (wid, "Color Paste");

	wid = toolbox_button ("Ascii", 0, toolbox, "Open ASCII Chart");
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (ascii_open), 0);

	for (i = 15; i; i--)
	{
		style = gtk_style_new ();
		style->bg[0] = colors[i];
		wid = toolbox_button ("  ", 0, toolbox, 0);
		gtk_widget_set_style (wid, style);
		gtk_signal_connect (GTK_OBJECT (wid), "clicked",
								  GTK_SIGNAL_FUNC (toolbox_color), (gpointer) i);
		gtk_style_unref (style);
	}

	wid = toolbox_button ("", "%U", toolbox, "Underline");
	gtk_label_parse_uline (GTK_LABEL (GTK_BIN (wid)->child), "_U");

	/*wid =*/ toolbox_button ("B", "%B", toolbox, "Bold");
	/*style = gtk_style_new ();
	gdk_font_unref (style->font);
   style->font = font_bold;
   gdk_font_ref (font_bold); 
	gtk_widget_set_style (GTK_BIN (wid)->child, style);
	gtk_style_unref (style);*/

	toolbox_button ("A", "%O", toolbox, "Plain Text");

	wid = gtk_button_new_with_label ("<");
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (maingui_toolbox), toolbox);
	gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 1);
	if (prefs.inputgad_superfocus)
		show_and_unfocus (wid);
	else
		gtk_widget_show (wid);
	add_tip (wid, "Open Toolbox");
/*
	wid = gtk_button_new_with_label ("^");
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (maingui_showhide_topic), sess);
	gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 1);
	gtk_widget_show (wid);
	add_tip (wid, "Show/Hide topic bar");*/
}

void
gui_create_standard_buttons (session * sess, GtkWidget * win,
									  GtkWidget * tbox)
{
	GtkWidget *wid;

#ifdef USE_GNOME
	wid =
		gtkutil_button (win, GNOME_STOCK_BUTTON_CANCEL, 0, X_session, sess, 0);
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	show_and_unfocus (wid);
	add_tip (wid, "Close Channel");

	wid =
		gtkutil_button (win, GNOME_STOCK_PIXMAP_REMOVE, 0, relink_window, sess,
							 0);
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	show_and_unfocus (wid);
	add_tip (wid, "Link/DeLink this tab");
#else
	wid = gtk_button_new_with_label ("X");
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (X_session), sess);
	show_and_unfocus (wid);
	add_tip (wid, "Close Channel");

	wid = gtk_button_new_with_label ("^");
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (relink_window), sess);
	show_and_unfocus (wid);
	add_tip (wid, "Link/DeLink this tab");
#endif

#ifdef USE_PANEL
	if (!nopanel)
	{
		wid = gtkutil_button (win, GNOME_STOCK_PIXMAP_BOTTOM,
									 0, maingui_panelize, sess, 0);
		gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
		add_tip (wid, "Panelize");
	}
#endif

#ifdef USE_GNOME
	wid =
		gtkutil_button (win, GNOME_STOCK_PIXMAP_BACK, 0, maingui_moveleft, 0,
							 0);
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	show_and_unfocus (wid);
	add_tip (wid, "Move tab left");

	wid =
		gtkutil_button (win, GNOME_STOCK_PIXMAP_FORWARD, 0, maingui_moveright,
							 0, 0);
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	show_and_unfocus (wid);
	add_tip (wid, "Move tab right");
#else
	wid = gtk_button_new_with_label ("<");
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (maingui_moveleft), 0);
	show_and_unfocus (wid);
	add_tip (wid, "Move tab left");

	wid = gtk_button_new_with_label (">");
	gtk_box_pack_start (GTK_BOX (tbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (maingui_moveright), 0);
	show_and_unfocus (wid);
	add_tip (wid, "Move tab right");
#endif
}

/*static void
ul_keypress_cb (GtkWidget *widget, GdkEventKey *event, session *sess)
{
	struct User *user;
	GSList *list = sess->userlist;
	int row = 0;

	while (list)
	{
		user = list->data;
		if (user->nick[0] == event->keyval)
		{
			gtk_clist_moveto (GTK_CLIST (sess->gui->namelistgad), row, 0, 0.5, 0);
			break;
		}
		list = list->next;
		row++;
	}
}*/

void
create_window (struct session *sess)
{
	GtkWidget *leftpane, *rightpane;
	GtkWidget *vbox, *tbox, *bbox, *nlbox, *wid;
	int justopened = FALSE;

	if (sess->is_dialog)
	{
		new_dialog (sess);
		if (prefs.treeview)
			tree_update ();
		return;
	}
	if (!sess->server->front_session)
		sess->server->front_session = sess;

	if (prefs.tabchannels)
	{
		sess->is_tab = TRUE;
		if (!main_window)
		{
			justopened = TRUE;
			gui_make_tab_window (sess);
		}
		sess->gui->window = gtk_hbox_new (0, 0);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "destroy",
								  GTK_SIGNAL_FUNC (gtk_kill_session_callback), sess);
		if (!current_tab)
		{
			current_tab = sess;
			fe_set_title (sess);
		}
	} else
	{

#ifdef USE_GNOME
		sess->gui->window = gnome_app_new ("X-Chat", "X-Chat");
#else
		sess->gui->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
#endif
		fe_set_title (sess);
		gtk_widget_realize (sess->gui->window);
		maingui_set_icon (sess->gui->window);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "destroy",
								  GTK_SIGNAL_FUNC (gtk_kill_session_callback), sess);
		gtk_signal_connect ((GtkObject *) sess->gui->window, "focus_in_event",
								  GTK_SIGNAL_FUNC (focus_in), sess);
		gtk_window_set_policy ((GtkWindow *) sess->gui->window, TRUE, TRUE,
									  FALSE);
	}

	palette_alloc (sess->gui->window);

	vbox = gtk_vbox_new (FALSE, 0);
	sess->gui->vbox = vbox;
	gtk_container_set_border_width ((GtkContainer *) vbox, 0);
	if (!prefs.tabchannels)
	{
#ifdef USE_GNOME
		gnome_app_set_contents (GNOME_APP (sess->gui->window), vbox);
#else
		gtk_container_add (GTK_CONTAINER (sess->gui->window), vbox);
#endif
	} else
		gtk_container_add ((GtkContainer *) sess->gui->window, vbox);
	gtk_widget_show (vbox);

	if (!prefs.tabchannels)
	{
#ifdef USE_GNOME
		sess->gui->menu = createmenus (sess->gui->window, sess, 1);
#else
		sess->gui->menu = createmenus (0, sess, 1);
		gtk_widget_show (sess->gui->menu);

		wid = gtk_handle_box_new ();
		gtk_container_add (GTK_CONTAINER (wid), sess->gui->menu);
		gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, TRUE, 0);
		gtk_widget_show (wid);
#endif
	}
	tbox = gtk_hbox_new (FALSE, 0);
	sess->gui->tbox = tbox;
	gtk_container_set_border_width (GTK_CONTAINER (tbox), 0);
	gtk_box_pack_start (GTK_BOX (vbox), tbox, FALSE, TRUE, 2);
	if (prefs.topicbar)
		gtk_widget_show (tbox);

	gui_create_standard_buttons (sess, sess->gui->window, tbox);

	if (!prefs.tabchannels)
	{
		sess->gui->changad = gtk_label_new ("<none>");
		gtk_box_pack_start (GTK_BOX (tbox), sess->gui->changad, FALSE, FALSE, 5);
		gtk_widget_show (sess->gui->changad);
	}

	sess->gui->topicgad = gtk_entry_new ();
	gtk_signal_connect (GTK_OBJECT (sess->gui->topicgad), "activate",
							  GTK_SIGNAL_FUNC (handle_topicgad), sess);
	gtk_container_add (GTK_CONTAINER (tbox), sess->gui->topicgad);
	if (prefs.inputgad_superfocus)
		show_and_unfocus (sess->gui->topicgad);
	else
		gtk_widget_show (sess->gui->topicgad);

	add_tip (sess->gui->topicgad, "The channel topic");

#ifdef USE_GNOMEE
	if (sess->is_tab)
		wid = gtkutil_button (main_window, GNOME_STOCK_PIXMAP_FORWARD, 0,
									 userlist_hide, sess, 0);
	else
		wid = gtkutil_button (sess->gui->window, GNOME_STOCK_PIXMAP_FORWARD, 0,
									 userlist_hide, sess, 0);
	gtk_box_pack_end (GTK_BOX (tbox), wid, 0, 0, 0);
#else
	if (prefs.hideuserlist)
		wid = gtk_button_new_with_label ("<");
	else
		wid = gtk_button_new_with_label (">");
	gtk_box_pack_end (GTK_BOX (tbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (userlist_hide), (gpointer) sess);
#endif
	show_and_unfocus (wid);
	add_tip (wid, "Hide/Show Userlist");

	if (!prefs.nochanmodebuttons)
	{
		sess->gui->key_entry = gtk_entry_new_with_max_length (16);
		gtk_widget_set_usize (sess->gui->key_entry, 30, -1);
		gtk_box_pack_end (GTK_BOX (tbox), sess->gui->key_entry, 0, 0, 0);
		gtk_signal_connect (GTK_OBJECT (sess->gui->key_entry), "activate",
								  GTK_SIGNAL_FUNC (key_entry), (gpointer) sess);
		if (prefs.inputgad_superfocus)
			show_and_unfocus (sess->gui->key_entry);
		else
			gtk_widget_show (sess->gui->key_entry);

		add_flag_wid (&(sess->gui->flag_k), "Keyword", tbox, "K", flagk_hit,
						  sess);

		sess->gui->limit_entry = gtk_entry_new_with_max_length (10);
		gtk_widget_set_usize (sess->gui->limit_entry, 30, -1);
		gtk_box_pack_end (GTK_BOX (tbox), sess->gui->limit_entry, 0, 0, 0);
		gtk_signal_connect (GTK_OBJECT (sess->gui->limit_entry), "activate",
								  GTK_SIGNAL_FUNC (limit_entry), (gpointer) sess);
		if (prefs.inputgad_superfocus)
			show_and_unfocus (sess->gui->limit_entry);
		else
			gtk_widget_show (sess->gui->limit_entry);

		add_flag_wid (&(sess->gui->flag_l), "User Limit", tbox, "L", flagl_hit,
						  sess);

		add_flag_wid (&(sess->gui->flag_m), "Moderated", tbox, "M", flagm_hit,
						  sess);

		add_flag_wid (&(sess->gui->flag_p), "Private", tbox, "P", flagp_hit,
						  sess);

		add_flag_wid (&(sess->gui->flag_i), "Invite Only", tbox, "I", flagi_hit,
						  sess);

		add_flag_wid (&(sess->gui->flag_s), "Secret", tbox, "S", flags_hit,
						  sess);

		add_flag_wid (&(sess->gui->flag_n), "No outside messages", tbox, "N",
						  flagn_hit, sess);

		add_flag_wid (&(sess->gui->flag_t), "Topic Protection", tbox, "T",
						  flagt_hit, sess);

	} else
		sess->gui->flag_wid[0] = 0;

	leftpane = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (leftpane);

	if (!prefs.nopaned)
	{
		sess->gui->paned = gtk_hpaned_new ();
		gtk_container_add (GTK_CONTAINER (vbox), sess->gui->paned);
		gtk_widget_show (sess->gui->paned);
	}
	rightpane = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (rightpane);
	sess->gui->userlistbox = rightpane;

	if (!prefs.nopaned)
	{
		gtk_paned_pack1 (GTK_PANED (sess->gui->paned), leftpane, TRUE, TRUE);
		gtk_paned_pack2 (GTK_PANED (sess->gui->paned), rightpane, FALSE, TRUE);
		gtk_paned_set_gutter_size (GTK_PANED (sess->gui->paned), 4);
	} else
	{
		wid = gtk_hbox_new (0, 2);
		gtk_container_add (GTK_CONTAINER (vbox), wid);
		gtk_widget_show (wid);
		gtk_container_add (GTK_CONTAINER (wid), leftpane);
		gtk_box_pack_end (GTK_BOX (wid), rightpane, 0, 0, 0);
	}

	sess->gui->nl_box = nlbox = gtk_vbox_new (FALSE, 1);
	gtk_container_add (GTK_CONTAINER (rightpane), nlbox);
	gtk_widget_show (nlbox);

	wid = gtk_frame_new (0);
	gtk_box_pack_start (GTK_BOX (nlbox), wid, 0, 0, 0);
	gtk_widget_show (wid);

	sess->gui->namelistinfo = gtk_label_new (" ");
	gtk_container_add (GTK_CONTAINER (wid), sess->gui->namelistinfo);
	gtk_widget_show (sess->gui->namelistinfo);

	maingui_create_textlist (sess, leftpane);
	sess->gui->leftpane = leftpane;

	if (prefs.showhostname_in_userlist)
	{
		sess->gui->namelistgad =
			gtkutil_clist_new (2, 0, nlbox, GTK_POLICY_AUTOMATIC,
									 maingui_userlist_selected, sess, 0, 0,
									 GTK_SELECTION_MULTIPLE);
		gtk_clist_set_column_auto_resize ((GtkCList *) sess->gui->namelistgad,
													 0, TRUE);
		gtk_clist_set_column_auto_resize ((GtkCList *) sess->gui->namelistgad,
													 1, TRUE);
	} else
	{
		sess->gui->namelistgad =
			gtkutil_clist_new (1, 0, nlbox, GTK_POLICY_AUTOMATIC,
									 maingui_userlist_selected, sess, 0, 0,
									 GTK_SELECTION_MULTIPLE);
	}

	GTK_WIDGET_UNSET_FLAGS (sess->gui->namelistgad, GTK_CAN_FOCUS);

	if (prefs.style_namelistgad)
		gtk_widget_set_style (sess->gui->namelistgad, inputgad_style);

#ifdef USE_GNOME
	/* set up drops */
	gtk_drag_dest_set (sess->gui->namelistgad, GTK_DEST_DEFAULT_ALL,
							 dnd_targets, 1,
							 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
	gtk_signal_connect (GTK_OBJECT (sess->gui->namelistgad), "drag_motion",
							  GTK_SIGNAL_FUNC (userlist_dnd_motion), 0);
	gtk_signal_connect (GTK_OBJECT (sess->gui->namelistgad), "drag_leave",
							  GTK_SIGNAL_FUNC (userlist_dnd_leave), 0);
	gtk_signal_connect (GTK_OBJECT (sess->gui->namelistgad),
							  "drag_data_received",
							  GTK_SIGNAL_FUNC (userlist_dnd_drop), sess);
#endif

	gtk_clist_set_selection_mode (GTK_CLIST (sess->gui->namelistgad),
											GTK_SELECTION_MULTIPLE);
	gtk_clist_set_column_width (GTK_CLIST (sess->gui->namelistgad), 0, 10);
	gtk_widget_set_usize (sess->gui->namelistgad->parent, 115, 0);
	gtk_signal_connect (GTK_OBJECT (sess->gui->namelistgad),
							  "button_press_event", GTK_SIGNAL_FUNC (ul_button_rel),
							  sess);
	/*gtk_signal_connect (GTK_OBJECT (sess->gui->namelistgad),
							  "key_press_event", GTK_SIGNAL_FUNC (ul_keypress_cb),
							  sess);*/

	if (prefs.lagometer)
	{
		sess->gui->lagometer = wid = gtk_progress_bar_new ();
		gtk_widget_set_usize (wid, 1, 8);
		gtk_box_pack_start (GTK_BOX (nlbox), wid, 0, 0, 0);
		gtk_widget_show (wid);
	}

	if (!prefs.nouserlistbuttons)
		maingui_createbuttons (sess);
	else
		sess->gui->button_box = 0;

	/* bottom hbox */
	bbox = gtk_hbox_new (FALSE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (bbox), 0);
	gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, TRUE, 2);
	gtk_widget_show (bbox);

	if (prefs.nickgad)
	{
		sess->gui->op_box = gtk_hbox_new (0, 0);
		gtk_box_pack_start (GTK_BOX (bbox), sess->gui->op_box, FALSE, FALSE, 2);
		gtk_widget_show (sess->gui->op_box);

		sess->gui->nickgad = gtk_label_new (sess->server->nick);
		gtk_box_pack_start (GTK_BOX (bbox), sess->gui->nickgad, FALSE, FALSE,
								  4);
		gtk_widget_show (sess->gui->nickgad);
	}

	sess->gui->inputgad = gtk_entry_new_with_max_length (2048);
	gtk_container_add (GTK_CONTAINER (bbox), sess->gui->inputgad);
	gtk_signal_connect (GTK_OBJECT (sess->gui->inputgad), "key_press_event",
							  GTK_SIGNAL_FUNC (key_handle_key_press), sess);
	if (prefs.style_inputbox)
		gtk_widget_set_style (sess->gui->inputgad, inputgad_style);
	gtk_widget_show (sess->gui->inputgad);
	if (prefs.newtabstofront || justopened)
		gtk_widget_grab_focus (sess->gui->inputgad);

	gui_create_toolbox (sess, bbox);

	gtk_widget_show (sess->gui->window);

	if (prefs.tabchannels)
	{
		sess->gui->changad = gtk_label_new ("<none>");
		gtk_widget_show (sess->gui->changad);

		gtk_notebook_append_page (GTK_NOTEBOOK (main_book), sess->gui->window,
										  sess->gui->changad);
		gtk_widget_realize (sess->gui->textgad);

		if (justopened)
		{
			gtk_widget_show (main_window);
			if (prefs.mainwindow_left || prefs.mainwindow_top)
				gdk_window_move (main_window->window,
									  prefs.mainwindow_left, prefs.mainwindow_top);
		}

		if (!normaltab_style)
			maingui_init_styles (sess->gui->changad->style);

		if (prefs.newtabstofront && !justopened)
		{
			maingui_pagetofront (gtk_notebook_page_num
										(GTK_NOTEBOOK (main_book), sess->gui->window));
			sess->new_data = TRUE;
			gui_new_tab (sess);
		}

		/* make switching tabs super smooth! */
		gtk_widget_realize (rightpane);
		gdk_window_set_background (rightpane->window,
											&rightpane->style->bg[GTK_STATE_NORMAL]);
		gdk_window_set_back_pixmap (main_book->window, 0, 0);
		gdk_window_set_background (((GtkNotebook*)main_book)->panel,
											&main_book->style->bg[GTK_STATE_NORMAL]);

	} else
	{
		if (!normaltab_style)
			maingui_init_styles (gtk_widget_get_style (sess->gui->changad));

		if (prefs.mainwindow_left || prefs.mainwindow_top)
			gdk_window_move (sess->gui->window->window,
								  prefs.mainwindow_left, prefs.mainwindow_top);
	}

	if (prefs.hideuserlist)
	{
		userlist_hide (0, sess);
		if (sess->gui->paned)
			sess->userlisthidden = GTK_PANED (sess->gui->paned)->handle_xpos;
	}

	if (prefs.hidemenu)
#ifdef USE_GNOME
		menu_showhide (sess, 1);
#else
		gtk_widget_hide (main_menu_bar);
#endif

	fe_set_nonchannel (sess, FALSE);
}

static void
maingui_delink_nontab (GtkWidget * wid, GtkWidget * box)
{
	GtkWidget *win;
	GtkWidget *label;
	gboolean need = FALSE;
	struct relink_data *rld;
	int page;

	g_assert (box);
	rld = gtk_object_get_user_data (GTK_OBJECT (box));
	g_assert (rld);

	if (rld->win == NULL)
	{

		win = gtk_window_new (GTK_WINDOW_TOPLEVEL);

		gtk_signal_connect ((GtkObject *) win, "destroy",
								  gtk_widget_destroy, box);

		page = gtk_notebook_page_num (GTK_NOTEBOOK (main_book), box);
		gtk_widget_reparent (box, win);

		rld->win = win;
		gtk_window_set_title (GTK_WINDOW (win), rld->ltitle);
		gtk_notebook_remove_page (GTK_NOTEBOOK (main_book), page);

		gtk_widget_show_all (win);
		rld->hbox = NULL;
	} else
	{
		if (main_book == NULL)
		{
			gui_make_tab_window (NULL);
			need = TRUE;
		}
		win = gtk_hbox_new (0, 0);
		gtk_widget_show (win);

		gtk_widget_reparent (box, win);
		gtk_signal_disconnect_by_data (GTK_OBJECT (rld->win), box);
		gtk_widget_destroy (GTK_WIDGET (rld->win));
		label = gtk_label_new (rld->stitle);
		gtk_widget_show (label);
		gtk_notebook_append_page (GTK_NOTEBOOK (main_book), win, label);
		if (prefs.newtabstofront)
		{
			gtk_idle_add ((GtkFunction) maingui_pagetofront, (gpointer)
							  gtk_notebook_page_num (GTK_NOTEBOOK (main_book), box));
		}
		gtk_widget_show_all (win);
		if (need)
			gtk_widget_show_all (main_window);
		rld->win = NULL;
		rld->hbox = win;
	}
}

static int
maingui_box_close (GtkWidget * wid, struct relink_data *rld)
{
	if (rld->win)
		gtk_widget_destroy (rld->win);
	if (rld->hbox)
		gtk_widget_destroy (rld->hbox);

	if (rld->close_callback)
		rld->close_callback (NULL, rld->userdata);

	free (rld->ltitle);
	g_free (rld);
	return 1;
}

GtkWidget *
maingui_new_tab (char *title, char *name, void *close_callback,
					  void *userdata)
{
	int page;
	GtkWidget *wid, *box, *label, *topbox;
	struct relink_data *rld = g_new0 (struct relink_data, 1);
	char *buf;

	topbox = gtk_hbox_new (0, 0);
	gtk_widget_show (topbox);

	box = gtk_vbox_new (0, 0);
	gtk_box_pack_start (GTK_BOX (box), topbox, 0, 0, 0);
	gtk_widget_show (box);

#ifdef USE_GNOME
	wid = gtkutil_button (main_book, GNOME_STOCK_BUTTON_CANCEL,
								 0, gtkutil_destroy, box, 0);
	gtk_box_pack_start (GTK_BOX (topbox), wid, 0, 0, 0);
	gtk_widget_show (wid);
	add_tip (wid, "Close Tab");
	wid = gtkutil_button (main_book, GNOME_STOCK_PIXMAP_REMOVE,
								 0, maingui_delink_nontab, box, 0);
	gtk_box_pack_start (GTK_BOX (topbox), wid, 0, 0, 0);
	gtk_widget_show (wid);
	add_tip (wid, "Relink");
#else
	wid = gtk_button_new_with_label ("X");
	gtk_box_pack_start (GTK_BOX (topbox), wid, 0, 0, 0);
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (gtkutil_destroy), box);
	gtk_widget_show (wid);
	add_tip (wid, "Close Tab");
	wid = gtk_button_new_with_label ("^");
	gtk_signal_connect (GTK_OBJECT (wid), "clicked",
							  GTK_SIGNAL_FUNC (maingui_delink_nontab), box);
	gtk_box_pack_start (GTK_BOX (topbox), wid, 0, 0, 0);
	gtk_widget_show (wid);
	add_tip (wid, "Relink");
#endif

	wid = gtk_label_new (title);
	gtk_container_add (GTK_CONTAINER (topbox), wid);
	gtk_widget_show (wid);

	gtk_signal_connect (GTK_OBJECT (box), "destroy",
							  GTK_SIGNAL_FUNC (maingui_box_close), rld);

	buf = malloc (strlen (name) + 3);
	sprintf (buf, "(%s)", name);
	label = gtk_label_new (buf);
	free (buf);
	gtk_widget_show (label);

	gtk_notebook_append_page (GTK_NOTEBOOK (main_book), box, label);

	if (prefs.newtabstofront)
	{
		page = gtk_notebook_page_num (GTK_NOTEBOOK (main_book), box);
		maingui_pagetofront (page);
	}

	rld->win = NULL;
	rld->stitle = name;
	rld->ltitle = strdup (title);
	rld->close_callback = close_callback;
	rld->userdata = userdata;

	gtk_object_set_user_data (GTK_OBJECT (box), rld);
	return box;
}

gint
gtk_kill_session_callback (GtkWidget * win, struct session * sess)
{
	kill_session_callback (sess);
	return TRUE;
}

void
fe_session_callback (struct session *sess)
{
	tree_update ();

#ifdef USE_PANEL
	if (sess->gui->panel_button)
		gtk_widget_destroy (sess->gui->panel_button);
#endif

	if (sess->gui->bar)
	{
		fe_progressbar_end (sess);
		sess->server->connecting = TRUE;
	}
	if (menu_sess == sess && sess_list)
		menu_sess = (struct session *) sess_list->data;

	if (sess->is_tab && main_book)
	{
		if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (main_book), 0) == NULL)
			gtk_widget_destroy (main_book);
	}
}

void
fe_server_callback (struct server *serv)
{
	/*if (serv->gui->rawlog_window)
	   { */
	/* we don't want the "destroy" callback to be called */
	/*gtk_signal_disconnect_by_data (GTK_OBJECT (serv->gui->rawlog_window), serv);
	   gtk_widget_destroy (serv->gui->rawlog_window);
	   } */
}

void
my_gtk_entry_set_text (GtkWidget * wid, char *text, struct session *sess)
{
	void *callback;
	if (sess->gui->flag_wid[0] == 0)
		return;
	if (wid == sess->gui->limit_entry)
		callback = (void *) limit_entry;
	else
		callback = (void *) key_entry;
	gtk_signal_disconnect_by_data (GTK_OBJECT (wid), sess);
	gtk_entry_set_text (GTK_ENTRY (wid), text);
	gtk_signal_connect (GTK_OBJECT (wid), "activate",
							  GTK_SIGNAL_FUNC (callback), sess);
}

static void
my_gtk_toggle_state (GtkWidget * wid, int state, char which,
							struct session *sess)
{
	void *callback;
	switch (which)
	{
	case 'k':
		callback = flagk_hit;
		break;
	case 'l':
		callback = flagl_hit;
		break;
	case 'm':
		callback = flagm_hit;
		break;
	case 'p':
		callback = flagp_hit;
		break;
	case 'i':
		callback = flagi_hit;
		break;
	case 's':
		callback = flags_hit;
		break;
	case 'n':
		callback = flagn_hit;
		break;
	case 't':
		callback = flagt_hit;
		break;
	default:
		gtk_toggle_button_set_active ((GtkToggleButton *) wid, state);
		return;
	}
	gtk_signal_disconnect_by_data (GTK_OBJECT (wid), sess);
	gtk_toggle_button_set_active ((GtkToggleButton *) wid, state);
	if (callback)
		gtk_signal_connect (GTK_OBJECT (wid), "toggled",
								  GTK_SIGNAL_FUNC (callback), sess);
}

void
fe_update_mode_buttons (struct session *sess, char mode, char sign)
{
	int state, i;

	if (sign == '+')
		state = TRUE;
	else
		state = FALSE;

	for (i = 0; i < sizeof (chan_flags); i++)
	{
		if (chan_flags[i] == mode)
		{
			if (state)
				sess->channelflags |= (1 << i);
			else
				sess->channelflags &= ~(1 << i);
		}
	}

	/* FIXME: it should use the new session->channelflags */
	if (sess->gui->flag_wid[0])
	{
		for (i = 0; i < 8; i++)
		{
			if (chan_flags[i] == mode)
			{
				if (GTK_TOGGLE_BUTTON (sess->gui->flag_wid[i])->active != state)
					my_gtk_toggle_state (sess->gui->flag_wid[i], state,
												chan_flags[i], sess);
			}
		}
	}

	fe_set_title (sess);
}

void
handle_inputgad (GtkWidget * igad, struct session *sess)
{
	char *cmd = gtk_entry_get_text (GTK_ENTRY (igad));

	if (cmd[0] == 0)
		return;

	handle_multiline (sess, cmd, TRUE, FALSE);

	gtk_entry_set_text (GTK_ENTRY (igad), "");
}
