Logo Search packages:      
Sourcecode: xchat version File versions

maingui.c

/* X-Chat
 * Copyright (C) 2002 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
 */

#define GTK_DISABLE_DEPRECATED

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include <gtk/gtkarrow.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkhpaned.h>
#include <gtk/gtkframe.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkprogressbar.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktable.h>
#include <gtk/gtknotebook.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkvscrollbar.h>

#include "../common/xchat.h"
#include "../common/fe.h"
#include "../common/server.h"
#include "../common/text.h"
#include "../common/xchatc.h"
#include "../common/outbound.h"
#include "../common/inbound.h"
#include "../common/plugin.h"
#include "../common/modes.h"
#include "fe-gtk.h"
#include "banlist.h"
#include "gtkutil.h"
#include "palette.h"
#include "maingui.h"
#include "menu.h"
#include "fkeys.h"
#include "userlistgui.h"
#include "tabs.h"
#include "xtext.h"

static void mg_create_entry (session *sess, GtkWidget *box);
static void mg_link_irctab (session *sess, int focus);

static session_gui static_mg_gui;
static session_gui *mg_gui = NULL;  /* the shared irc tab */
static int ignore_chanmode = FALSE;
static const char chan_flags[] = { 't', 'n', 's', 'i', 'p', 'm', 'l', 'k' };

static GtkWidget *active_tab = NULL;      /* active tab - toggle button */
GtkWidget *parent_window = NULL;                /* the master window */

GtkStyle *input_style;

static PangoAttrList *newdata_list;
static PangoAttrList *nickseen_list;
static PangoAttrList *newmsg_list;
static PangoAttrList *plain_list = NULL;


static PangoAttrList *
mg_attr_list_create (GdkColor *col)
{
      PangoAttribute *attr;
      PangoAttrList *list;

      list = pango_attr_list_new ();

      if (col)
      {
            attr = pango_attr_foreground_new (col->red, col->green, col->blue);
            attr->start_index = 0;
            attr->end_index = 0xffff;
            pango_attr_list_insert (list, attr);
      }

      if (prefs.tab_small)
      {
#ifdef WIN32
            attr = pango_attr_scale_new (PANGO_SCALE_SMALL);
#else
            attr = pango_attr_scale_new (PANGO_SCALE_X_SMALL);
#endif
            attr->start_index = 0;
            attr->end_index = 0xffff;
            pango_attr_list_insert (list, attr);
      }

      return list;
}

static void
mg_create_tab_colors (void)
{
      if (plain_list)
      {
            pango_attr_list_unref (plain_list);
            pango_attr_list_unref (newmsg_list);
            pango_attr_list_unref (newdata_list);
            pango_attr_list_unref (nickseen_list);
      }

      plain_list = mg_attr_list_create (NULL);
      newdata_list = mg_attr_list_create (&colors[COL_NEW_DATA]);
      nickseen_list = mg_attr_list_create (&colors[COL_HILIGHT]);
      newmsg_list = mg_attr_list_create (&colors[COL_NEW_MSG]);
}

#ifdef WIN32
#define WINVER 0x0501   /* needed for vc6? */
#include <windows.h>
#include <gdk/gdkwin32.h>

/* Flash the taskbar button on Windows when there's a highlight event. */

static void
flash_window (GtkWidget *win)
{
      FLASHWINFO fi;
      static HMODULE user = NULL;
      static BOOL (*flash) (PFLASHWINFO) = NULL;

      if (!user)
      {
            user = GetModuleHandleA ("USER32");
            if (!user)
                  return;     /* this should never fail */
      }

      if (!flash)
      {
            flash = (void *)GetProcAddress (user, "FlashWindowEx");
            if (!flash)
                  return;     /* this fails on NT4.0 and Win95 */
      }

      fi.cbSize = sizeof (fi);
      fi.hwnd = GDK_WINDOW_HWND (win->window);
      fi.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG;
      fi.uCount = 0;
      fi.dwTimeout = 500;
      flash (&fi);
      /*FlashWindowEx (&fi);*/
}
#endif

/* set a tab plain, red, light-red, or blue */

void
fe_set_tab_color (struct session *sess, int col, int flash)
{
      if (sess->gui->is_tab && (col == 0 || sess != current_tab))
      {
            switch (col)
            {
            case 0:     /* no particular color (theme default) */
                  sess->new_data = FALSE;
                  sess->msg_said = FALSE;
                  sess->nick_said = FALSE;
                  tab_set_attrlist (sess->res->tab, plain_list);
                  break;
            case 1:     /* new data has been displayed (dark red) */
                  sess->new_data = TRUE;
                  sess->msg_said = FALSE;
                  sess->nick_said = FALSE;
                  tab_set_attrlist (sess->res->tab, newdata_list);
                  break;
            case 2:     /* new message arrived in channel (light red) */
                  sess->new_data = FALSE;
                  sess->msg_said = TRUE;
                  sess->nick_said = FALSE;
                  tab_set_attrlist (sess->res->tab, newmsg_list);
                  break;
            case 3:     /* your nick has been seen (blue) */
                  sess->new_data = FALSE;
                  sess->msg_said = FALSE;
                  sess->nick_said = TRUE;
                  tab_set_attrlist (sess->res->tab, nickseen_list);
                  break;
            }
      }

#ifdef WIN32
      if (flash && prefs.flash_hilight)
            flash_window (sess->gui->window);
#endif
}

/* change the little icon to the left of your nickname */

void
mg_set_access_icon (session_gui *gui, GdkPixbuf *pix)
{
      if (gui->op_xpm)
      {
            gtk_widget_destroy (gui->op_xpm);
            gui->op_xpm = 0;
      }

      if (pix)
      {
            gui->op_xpm = gtk_image_new_from_pixbuf (pix);
            gtk_box_pack_start (GTK_BOX (gui->nick_box), gui->op_xpm, 0, 0, 0);
            gtk_widget_show (gui->op_xpm);
      }
}

static gboolean
mg_inputbox_focus (GtkWidget *widget, GdkEventFocus *event, session_gui *gui)
{
      GSList *list;
      session *sess;

      if (gui->is_tab)
            return FALSE;

      list = sess_list;
      while (list)
      {
            sess = list->data;
            if (sess->gui == gui)
            {
                  current_sess = sess;
                  if (!sess->server->server_session)
                        sess->server->server_session = sess;
                  break;
            }
            list = list->next;
      }

      return FALSE;
}

static void
mg_inputbox_cb (GtkWidget *igad, session_gui *gui)
{
      char *cmd = GTK_ENTRY (igad)->text;
      static int ignore = FALSE;
      GSList *list;
      session *sess = NULL;

      if (ignore)
            return;

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

      cmd = strdup (cmd);

      /* avoid recursive loop */
      ignore = TRUE;
      gtk_entry_set_text (GTK_ENTRY (igad), "");
      ignore = FALSE;

      /* where did this event come from? */
      if (gui->is_tab)
      {
            sess = current_tab;
      } else
      {
            list = sess_list;
            while (list)
            {
                  sess = list->data;
                  if (sess->gui == gui)
                        break;
                  list = list->next;
            }
            if (!list)
                  sess = NULL;
      }

      if (sess)
            handle_multiline (sess, cmd, TRUE, FALSE);
      free (cmd);
}

void
fe_set_title (session *sess)
{
      char tbuf[256];
      int type;

      if (sess->gui->is_tab && sess != current_tab)
            return;

      type = sess->type;

      if (sess->server->connected == FALSE && sess->type != SESS_DIALOG)
            goto def;

      switch (type)
      {
      case SESS_DIALOG:
            snprintf (tbuf, sizeof (tbuf), "X-Chat ["VERSION"]: %s %s @ %s",
                               _("Dialog with"), sess->channel, sess->server->servername);
            break;
      case SESS_SERVER:
            snprintf (tbuf, sizeof (tbuf), "X-Chat ["VERSION"]: %s @ %s",
                               sess->server->nick, sess->server->servername);
            break;
      case SESS_CHANNEL:
            snprintf (tbuf, sizeof (tbuf),
                               "X-Chat ["VERSION"]: %s @ %s / %s (%s)",
                               sess->server->nick, sess->server->servername,
                               sess->channel, sess->current_modes ? sess->current_modes : "");
            break;
      case SESS_NOTICES:
      case SESS_SNOTICES:
            snprintf (tbuf, sizeof (tbuf), "X-Chat ["VERSION"]: %s @ %s (notices)",
                               sess->server->nick, sess->server->servername);
            break;
      default:
      def:
            gtk_window_set_title (GTK_WINDOW (sess->gui->window), "X-Chat ["VERSION"]");
            return;
      }

      gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf);
}

static gboolean
mg_windowstate_cb (GtkWidget *wid, GdkEvent *event, gpointer userdata)
{
      prefs.gui_win_state = 0;
      if (gdk_window_get_state (wid->window) & GDK_WINDOW_STATE_MAXIMIZED)
            prefs.gui_win_state = 1;

      return FALSE;
}

static gboolean
mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
{
      if (sess == NULL)             /* for the main_window */
      {
            if (mg_gui)
            {
                  if (prefs.mainwindow_save)
                  {
                        sess = current_sess;
                        gtk_window_get_position (GTK_WINDOW (wid), &prefs.mainwindow_left,
                                                                         &prefs.mainwindow_top);
                        gtk_window_get_size (GTK_WINDOW (wid), &prefs.mainwindow_width,
                                                                  &prefs.mainwindow_height);
                  }
            }
      }

      if (sess)
      {
            if (sess->type == SESS_DIALOG && prefs.mainwindow_save)
            {
                  gtk_window_get_position (GTK_WINDOW (wid), &prefs.dialog_left,
                                                                   &prefs.dialog_top);
                  gtk_window_get_size (GTK_WINDOW (wid), &prefs.dialog_width,
                                                            &prefs.dialog_height);
            }

            if (((GtkXText *) sess->gui->xtext)->transparent)
                  gtk_widget_queue_draw (sess->gui->xtext);
      }

      return FALSE;
}

/* move to a non-irc tab */

static void
mg_show_generic_tab (GtkWidget *button)
{
      GtkWidget *box;
      int num;
      GtkWidget *f = NULL;

      if (current_sess && GTK_WIDGET_HAS_FOCUS (current_sess->gui->input_box))
            f = current_sess->gui->input_box;

      box = g_object_get_data (G_OBJECT (button), "box");
      num = gtk_notebook_page_num (GTK_NOTEBOOK (mg_gui->note_book), box);
      gtk_notebook_set_current_page (GTK_NOTEBOOK (mg_gui->note_book), num);
      gtk_window_set_title (GTK_WINDOW (mg_gui->window),
                                                 g_object_get_data (G_OBJECT (button), "title"));
      gtk_widget_set_sensitive (mg_gui->menu, FALSE);

      if (f)
            gtk_widget_grab_focus (f);
}

/* a channel has been focused */

static void
mg_focus (session *sess)
{
      if (sess->gui->is_tab)
            current_tab = sess;
      current_sess = sess;

      /* dirty trick to avoid auto-selection */
      GTK_ENTRY (sess->gui->input_box)->editable = 0;
      gtk_widget_grab_focus (sess->gui->input_box);
      GTK_ENTRY (sess->gui->input_box)->editable = 1;

      sess->server->front_session = sess;

      if (sess->server->server_session != NULL)
      {
            if (sess->server->server_session->type != SESS_SERVER)
                  sess->server->server_session = sess;
      } else
      {
            sess->server->server_session = sess;
      }

      if (sess->new_data || sess->nick_said || sess->msg_said)
      {
            sess->nick_said = FALSE;
            sess->msg_said = FALSE;
            sess->new_data = FALSE;
            fe_set_tab_color (sess, 0, FALSE);
      }
}

static int
mg_progressbar_update (GtkWidget *bar)
{
      static int type = 0;
      static float pos = 0;

      pos += 0.05;
      if (pos >= 0.99)
      {
            if (type == 0)
            {
                  type = 1;
                  gtk_progress_bar_set_orientation ((GtkProgressBar *) bar,
                                                                                     GTK_PROGRESS_RIGHT_TO_LEFT);
            } else
            {
                  type = 0;
                  gtk_progress_bar_set_orientation ((GtkProgressBar *) bar,
                                                                                     GTK_PROGRESS_LEFT_TO_RIGHT);
            }
            pos = 0.05;
      }
      gtk_progress_bar_set_fraction ((GtkProgressBar *) bar, pos);
      return 1;
}

void
mg_progressbar_create (session_gui *gui)
{
      gui->bar = gtk_progress_bar_new ();
      gtk_box_pack_start (GTK_BOX (gui->nick_box), gui->bar, 0, 0, 0);
      gtk_widget_show (gui->bar);
      gui->bartag = fe_timeout_add (50, mg_progressbar_update, gui->bar);
}

void
mg_progressbar_destroy (session_gui *gui)
{
      fe_timeout_remove (gui->bartag);
      gtk_widget_destroy (gui->bar);
      gui->bar = 0;
      gui->bartag = 0;
}

/* switching tabs away from this one, so remember some info about it! */

static void
mg_unpopulate (session *sess)
{
      restore_gui *res;
      session_gui *gui;
      int i;

      gui = sess->gui;
      res = sess->res;

      if (gui->pane && sess->type == SESS_CHANNEL)
            prefs.paned_pos = gui->pane_pos = gtk_paned_get_position (GTK_PANED (gui->pane));

      res->input_text = strdup (GTK_ENTRY (gui->input_box)->text);
      res->topic_text = strdup (GTK_ENTRY (gui->topic_entry)->text);
      res->limit_text = strdup (GTK_ENTRY (gui->limit_entry)->text);
      res->key_text = strdup (GTK_ENTRY (gui->key_entry)->text);
      if (gui->laginfo)
            res->lag_text = strdup (gtk_label_get_text (GTK_LABEL (gui->laginfo)));
      if (gui->throttleinfo)
            res->queue_text = strdup (gtk_label_get_text (GTK_LABEL (gui->throttleinfo)));

      for (i = 0; i < NUM_FLAG_WIDS - 1; i++)
            res->flag_wid_state[i] = GTK_TOGGLE_BUTTON (gui->flag_wid[i])->active;

      res->old_ul_value = userlist_get_value (gui->user_tree);
      if (gui->lagometer)
            res->lag_value = gtk_progress_bar_get_fraction (
                                                                              GTK_PROGRESS_BAR (gui->lagometer));
      if (gui->throttlemeter)
            res->queue_value = gtk_progress_bar_get_fraction (
                                                                              GTK_PROGRESS_BAR (gui->throttlemeter));

      if (gui->bar)
      {
            res->c_graph = TRUE;    /* still have a graph, just not visible now */
            mg_progressbar_destroy (gui);
      }
}

static void
mg_restore_label (GtkWidget *label, char **text)
{
      if (!label)
            return;

      if (*text)
      {
            gtk_label_set_text (GTK_LABEL (label), *text);
            free (*text);
            *text = NULL;
      } else
      {
            gtk_label_set_text (GTK_LABEL (label), "");
      }
}

static void
mg_restore_entry (GtkWidget *entry, char **text)
{
      if (*text)
      {
            gtk_entry_set_text (GTK_ENTRY (entry), *text);
            free (*text);
            *text = NULL;
      } else
      {
            gtk_entry_set_text (GTK_ENTRY (entry), "");
      }
      gtk_editable_set_position (GTK_EDITABLE (entry), -1);
}

void
mg_set_topic_tip (session *sess)
{
      char buf[512];

      switch (sess->type)
      {
      case SESS_CHANNEL:
            if (sess->topic)
            {
                  snprintf (buf, sizeof (buf), _("Topic for %s is: %s"), sess->channel,
                                     sess->topic);
                  add_tip (sess->gui->topic_entry, buf);
            } else
                  add_tip (sess->gui->topic_entry, _("No topic is set"));
            break;
      default:
            if (GTK_ENTRY (sess->gui->topic_entry)->text &&
                   GTK_ENTRY (sess->gui->topic_entry)->text[0])
                  add_tip (sess->gui->topic_entry, GTK_ENTRY (sess->gui->topic_entry)->text);
            else
                  add_tip (sess->gui->topic_entry, ""); /* hSP: set topic to empty in case it isn't set.. */
      }
}

static int ul_tag = 0;

static gboolean
mg_populate_userlist (session *sess)
{
      session_gui *gui;

      if (!sess)
            sess = current_tab;

      if (is_session (sess))
      {
            gui = sess->gui;
            if (sess->type == SESS_DIALOG)
                  mg_set_access_icon (sess->gui, NULL);
            else
                  mg_set_access_icon (sess->gui, get_user_icon (sess->server, sess->res->myself));
            userlist_show (sess);
            userlist_set_value (sess->gui->user_tree, sess->res->old_ul_value);
      }

      ul_tag = 0;
      return 0;
}

/* fill the irc tab with a new channel */

static void
mg_populate (session *sess)
{
      session_gui *gui = sess->gui;
      restore_gui *res = sess->res;
      int i, vis, render = TRUE;

      if (gui->pane)
            vis = gui->ul_hidden;
      else
            vis = GTK_WIDGET_VISIBLE (gui->user_box);

      switch (sess->type)
      {
      case SESS_DIALOG:
            /* show the dialog buttons */
            gtk_widget_show (gui->dialogbutton_box);
            /* hide the chan-mode buttons */
            gtk_widget_hide (gui->topicbutton_box);
            /* hide the userlist */
            mg_userlist_showhide (sess, FALSE);
            break;
      case SESS_SERVER:
            if (prefs.chanmodebuttons)
                  gtk_widget_show (gui->topicbutton_box);
            /* hide the dialog buttons */
            gtk_widget_hide (gui->dialogbutton_box);
            /* hide the userlist */
            mg_userlist_showhide (sess, FALSE);
            break;
      default:
            /* hide the dialog buttons */
            gtk_widget_hide (gui->dialogbutton_box);
            if (prefs.chanmodebuttons)
                  gtk_widget_show (gui->topicbutton_box);
            /* show the userlist */
            mg_userlist_showhide (sess, TRUE);
      }

      /* move to THE irc tab */
      if (gui->is_tab)
            gtk_notebook_set_current_page (GTK_NOTEBOOK (gui->note_book), 0);

      if (gui->pane)
      {
            /* no change? then there will be no expose, so render now */
            if (vis != gui->ul_hidden && gui->user_box->allocation.width > 1)
                  render = FALSE;
      } else
      {
            /* userlist CHANGED? Let the pending exposure draw the xtext */
            if (vis && !GTK_WIDGET_VISIBLE (gui->user_box))
                  render = FALSE;
            if (!vis && GTK_WIDGET_VISIBLE (gui->user_box))
                  render = FALSE;
      }

      gtk_xtext_buffer_show (GTK_XTEXT (gui->xtext), res->buffer, render);
      GTK_XTEXT (gui->xtext)->color_paste = sess->color_paste;

      if (gui->is_tab)
            gtk_widget_set_sensitive (gui->menu, TRUE);

      /* restore all the GtkEntry's */
      mg_restore_entry (gui->topic_entry, &res->topic_text);
      mg_restore_entry (gui->input_box, &res->input_text);
      mg_restore_entry (gui->key_entry, &res->key_text);
      mg_restore_entry (gui->limit_entry, &res->limit_text);
      mg_restore_label (gui->laginfo, &res->lag_text);
      mg_restore_label (gui->throttleinfo, &res->queue_text);

      mg_focus (sess);
      fe_set_title (sess);

      /* this one flickers, so only change if necessary */
      if (strcmp (sess->server->nick, gtk_button_get_label (GTK_BUTTON (gui->nick_label))) != 0)
            gtk_button_set_label (GTK_BUTTON (gui->nick_label), sess->server->nick);

      /* this is slow, so make it a timeout event */
      if (!gui->is_tab)
      {
            mg_populate_userlist (sess);
      } else
      {
            if (ul_tag == 0)
                  ul_tag = g_idle_add ((GSourceFunc)mg_populate_userlist, NULL);
      }

      fe_userlist_numbers (sess);

      /* restore all the channel mode buttons */
      ignore_chanmode = TRUE;
      for (i = 0; i < NUM_FLAG_WIDS - 1; i++)
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gui->flag_wid[i]),
                                                                        res->flag_wid_state[i]);
      ignore_chanmode = FALSE;

      if (gui->lagometer)
            gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui->lagometer),
                                                                         res->lag_value);
      if (gui->throttlemeter)
            gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui->throttlemeter),
                                                                         res->queue_value);

      /* did this tab have a connecting graph? restore it.. */
      if (res->c_graph)
      {
            res->c_graph = FALSE;
            mg_progressbar_create (gui);
      }

      GTK_CHECK_MENU_ITEM (gui->away_item)->active = sess->server->is_away;

      mg_set_topic_tip (sess);

      plugin_emit_dummy_print (sess, "Focus Tab");
}

void
mg_bring_tofront (GtkWidget *tab)
{
      session *sess;

      sess = g_object_get_data (G_OBJECT (tab), "sess");
      if (!sess)
      {
            /* non-irc tab */
            if (GTK_IS_WINDOW (tab))
                  gtk_window_present (GTK_WINDOW (tab));
            else
                  tab_focus (tab);
      } else
      {
            if (sess && !sess->gui->is_tab)
            {
                  gtk_window_present (GTK_WINDOW (sess->gui->window));
                  return;
            }
            tab_focus (tab);
      }
}

void
mg_switch_page (int relative, int num)
{
      if (mg_gui)
            tab_group_switch (mg_gui->tabs_box, relative, num);
}

static void
mg_find_replacement_focus (GtkWidget *tab)
{
      mg_switch_page (TRUE, -1);
}

static void
mg_gendestroy (GtkWidget *tab)
{
      char *title;

      title = g_object_get_data (G_OBJECT (tab), "title");
/*    printf("enter mg_gendestroy (title=%s)\n", title);*/
      free (title);

      if (!xchat_is_quitting)
            gtk_widget_destroy (g_object_get_data (G_OBJECT (tab), "box"));
}

/* a toplevel IRC window was destroyed */

static void
mg_topdestroy_cb (GtkWidget *win, session *sess)
{
/*    printf("enter mg_topdestroy. sess %p was destroyed\n", sess);*/

      /* kill the user list */
      g_object_unref (G_OBJECT (sess->res->user_model));

      kill_session_callback (sess); /* tell xchat.c about it */
}

/* an IRC tab was destroyed */

static void
mg_ircdestroy (GtkWidget *tab, session *sess)
{
      GSList *list;

      /* kill the text buffer */
      gtk_xtext_buffer_free (sess->res->buffer);
      /* kill the user list */
      g_object_unref (G_OBJECT (sess->res->user_model));

      kill_session_callback (sess); /* tell xchat.c about it */

      if (mg_gui == NULL)
      {
/*          puts("-> mg_gui is already NULL");*/
            return;
      }

      list = sess_list;
      while (list)
      {
            sess = list->data;
            if (sess->gui->is_tab)
            {
/*                puts("-> some tabs still remain");*/
                  return;
            }
            list = list->next;
      }

/*    puts("-> no tabs left, killing main tabwindow");*/
      gtk_widget_destroy (mg_gui->window);
      active_tab = NULL;
      mg_gui = NULL;
      parent_window = NULL;
}

/* a tab has been destroyed */

static void
mg_tabdestroy_cb (GtkWidget *tab, session *sess)
{
      if (tab == active_tab && !xchat_is_quitting)
            mg_find_replacement_focus (tab);

      if (sess == NULL)
            mg_gendestroy (tab);
      else
      {
            if (!xchat_is_quitting)
                  tab_group_cleanup (sess->gui->tabs_box);
            mg_ircdestroy (tab, sess);
      }
}

static void
mg_tree_cb (GtkWidget *item, session *sess)
{
      if (is_session (sess))
      {
            if (sess->gui->is_tab)
                  mg_bring_tofront (sess->res->tab);
            else
                  gtk_window_present (GTK_WINDOW (sess->gui->window));
      }
}

static void
mg_colorpaste_cb (GtkCheckMenuItem *item, session *sess)
{
      sess->color_paste = FALSE;
      if (item->active)
            sess->color_paste = TRUE;
      GTK_XTEXT (sess->gui->xtext)->color_paste = sess->color_paste;
}

static void
mg_beepmsg_cb (GtkCheckMenuItem *item, session *sess)
{
      sess->beep = FALSE;
      if (item->active)
            sess->beep = TRUE;
}

static void
mg_hidejp_cb (GtkCheckMenuItem *item, session *sess)
{
      sess->hide_join_part = TRUE;
      if (item->active)
            sess->hide_join_part = FALSE;
}

static void
mg_create_sess_tree (GtkWidget *menu)
{
      GtkWidget *top_item, *item, *submenu;
      GSList *list, *ilist;
      server *serv;
      session *sess;

      list = serv_list;
      while (list)
      {
            serv = list->data;

            if (serv->servername[0] == 0)
                  top_item = gtk_menu_item_new_with_label (_("<none>"));
            else
                  top_item = gtk_menu_item_new_with_label (get_network (serv->front_session, TRUE));

            gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), top_item);
            gtk_widget_show (top_item);

            submenu = gtk_menu_new ();

            ilist = sess_list;
            while (ilist)
            {
                  sess = ilist->data;
                  if (sess->server == serv)
                  {
                        if (sess->channel[0] == 0)
                              item = gtk_menu_item_new_with_label (_("<none>"));
                        else
                              item = gtk_menu_item_new_with_label (sess->channel);
                        g_signal_connect (G_OBJECT (item), "activate",
                                                            G_CALLBACK (mg_tree_cb), sess);
                        gtk_menu_shell_prepend (GTK_MENU_SHELL (submenu), item);
                        gtk_widget_show (item);
                  }
                  ilist = ilist->next;
            }

            gtk_menu_item_set_submenu (GTK_MENU_ITEM (top_item), submenu);

            list = list->next;
      }
}

static void
mg_menu_destroy (GtkMenuShell *menushell, GtkWidget *menu)
{
      gtk_widget_destroy (menu);
}

static void
mg_create_icon_item (char *label, char *stock, GtkWidget *menu,
                                          void *callback, void *userdata)
{
      GtkWidget *item;

      item = create_icon_menu (label, stock, TRUE);
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback),
                                          userdata);
      gtk_widget_show (item);
}

static void
mg_quit_cb (GtkDialog *dialog, gint arg1, gpointer userdata)
{
      gtk_widget_destroy (GTK_WIDGET (dialog));
      if (arg1 == GTK_RESPONSE_YES)
            mg_safe_quit ();
}

static void
mg_close_sess (session *sess)
{
      GtkWidget *dialog;

      if (sess_list->next == NULL)
      {
            dialog = gtk_message_dialog_new (NULL, 0,
                                                            GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
                                                            _("No other tabs open, quit xchat?"));
            g_signal_connect (G_OBJECT (dialog), "response",
                                                G_CALLBACK (mg_quit_cb), NULL);
            gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
            gtk_widget_show (dialog);
            return;
      }

      fe_close_window (sess);
}

static void
mg_detach_tab_cb (GtkWidget *item, session *sess)
{
      mg_link_irctab (sess, 0);
}

static void
mg_destroy_tab_cb (GtkWidget *item, GtkWidget *tab)
{
      session *sess;

      sess = g_object_get_data (G_OBJECT (tab), "sess");
      if (sess)
            mg_close_sess (sess);
      else
            gtk_widget_destroy (tab);
}

static void
mg_color_insert (GtkWidget *item, gpointer userdata)
{
      char buf[32];

      sprintf (buf, "\003%02d", GPOINTER_TO_INT (userdata));
      key_action_insert (current_sess->gui->input_box, 0, buf, 0, 0);
}

static void
mg_create_color_menu (GtkWidget *menu, session *sess)
{
      GtkWidget *item;
      GtkWidget *submenu;
      char buf[256];
      int i;

      item = gtk_menu_item_new_with_label (_("Insert color code"));
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
      gtk_widget_show (item);

      submenu = gtk_menu_new ();
      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
      gtk_widget_show (submenu);

      for (i = 0; i < 16; i++)
      {
            item = gtk_menu_item_new_with_label ("");
            sprintf (buf, "<sup>%02d</sup> <span background=\"#%02x%02x%02x\">"
                              "            </span>",
                        i, colors[i].red >> 8, colors[i].green >> 8, colors[i].blue >> 8);
            gtk_label_set_markup (GTK_LABEL (GTK_BIN (item)->child), buf);
            g_signal_connect (G_OBJECT (item), "activate",
                                                G_CALLBACK (mg_color_insert), GINT_TO_POINTER (i));
            gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
            gtk_widget_show (item);
      }
}

static gboolean
mg_tab_press_cb (GtkWidget *wid, GdkEventButton *event, session *sess)
{
      GtkWidget *menu, *submenu, *item;

      /* shift-click to close a tab */
      if (event->state & GDK_SHIFT_MASK)
      {
            if (sess)
                  mg_close_sess (sess);
            else
                  gtk_widget_destroy (wid);
            return FALSE;
      }

      if (event->button != 3)
            return FALSE;

      menu = gtk_menu_new ();

      if (sess)
      {
            item = gtk_menu_item_new_with_label (sess->channel[0] ? sess->channel : _("<none>"));
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);

            submenu = gtk_menu_new ();

            menu_toggle_item (_("Beep on message"), submenu, mg_beepmsg_cb, sess,
                                                sess->beep);
            if (sess->type == SESS_CHANNEL)
                  menu_toggle_item (_("Show join/part messages"), submenu, mg_hidejp_cb,
                                                      sess, !sess->hide_join_part);
            menu_toggle_item (_("Color paste"), submenu, mg_colorpaste_cb, sess,
                                                sess->color_paste);

            gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
            gtk_widget_show (item);
      }

      if (sess)
            mg_create_color_menu (menu, sess);

      item = gtk_menu_item_new_with_label (_("Go to"));
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);

      submenu = gtk_menu_new ();
      mg_create_sess_tree (submenu);
      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
      gtk_widget_show (item);

      /* separator */
      item = gtk_menu_item_new ();
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
      gtk_widget_show (item);

      mg_create_icon_item (_("Close Tab"), GTK_STOCK_CLOSE, menu,
                                                mg_destroy_tab_cb, wid);
      if (sess)
            mg_create_icon_item (_("Detach Tab"), GTK_STOCK_REDO, menu,
                                                      mg_detach_tab_cb, sess);

      if (sess && tabmenu_list)
            menu_create (menu, tabmenu_list, sess->channel, FALSE);

      g_signal_connect (G_OBJECT (menu), "selection-done",
                                          G_CALLBACK (mg_menu_destroy), menu);
      gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event->time);
      return TRUE;
}

/* add a tabbed channel */

static void
mg_add_chan (session *sess)
{
      char *name = _("<none>");

      if (sess->channel[0])
            name = sess->channel;

      sess->res->tab = tab_group_add (sess->gui->tabs_box, name, sess->server,
                                                                    sess, mg_tab_press_cb, mg_link_cb,
                                                                    prefs.truncchans, prefs.tab_dnd);
      if (plain_list == NULL)
            mg_create_tab_colors ();

      tab_set_attrlist (sess->res->tab, plain_list);
      g_object_set_data (G_OBJECT (sess->res->tab), "sess", sess);

      g_signal_connect (G_OBJECT (sess->res->tab), "destroy",
                                    G_CALLBACK (mg_tabdestroy_cb), sess);

      if (sess->res->buffer == NULL)
      {
            sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext));
            gtk_xtext_set_time_stamp (sess->res->buffer, prefs.timestamp);
            sess->res->user_model = userlist_create_model ();
      }
}

static void
mg_userlist_button (GtkWidget * box, char *label, char *cmd,
                                      int a, int b, int c, int d)
{
      GtkWidget *wid = gtk_button_new_with_label (label);
      g_signal_connect (G_OBJECT (wid), "clicked",
                                          G_CALLBACK (userlist_button_cb), cmd);
      gtk_table_attach_defaults (GTK_TABLE (box), wid, a, b, c, d);
      show_and_unfocus (wid);
}

static GtkWidget *
mg_create_userlistbuttons (GtkWidget *box)
{
      struct popup *pop;
      GSList *list = button_list;
      int a = 0, b = 0;
      GtkWidget *tab;

      tab = gtk_table_new (5, 2, FALSE);
      gtk_box_pack_end (GTK_BOX (box), tab, FALSE, FALSE, 0);

      while (list)
      {
            pop = list->data;
            if (pop->cmd[0])
            {
                  mg_userlist_button (tab, pop->name, pop->cmd, a, a + 1, b, b + 1);
                  a++;
                  if (a == 2)
                  {
                        a = 0;
                        b++;
                  }
            }
            list = list->next;
      }

      return tab;
}

void
mg_chanmodebuttons_showhide (session *sess, int show)
{
      switch (sess->type)
      {
      case SESS_SERVER:
      case SESS_DIALOG:
            show = FALSE;
      }

      if (show)
            gtk_widget_show (sess->gui->topicbutton_box);
      else
            gtk_widget_hide (sess->gui->topicbutton_box);
}

void
mg_userlist_showhide (session *sess, int show)
{
      session_gui *gui = sess->gui;

      if (!show || prefs.hideuserlist)
      {
            if (gui->pane)
                  gtk_paned_set_position (GTK_PANED (gui->pane), 9999);
            gtk_widget_hide (gui->user_box);
            sess->gui->ul_hidden = 1;
      } else
      {
            if (gui->pane)
                  gtk_paned_set_position (GTK_PANED (gui->pane), gui->pane_pos);
            gtk_widget_show (gui->user_box);
            sess->gui->ul_hidden = 0;
      }
}

static void
mg_userlist_toggle_cb (GtkWidget *button, gpointer userdata)
{
      session_gui *gui = current_sess->gui;

      if (GTK_WIDGET_VISIBLE (gui->user_box))
      {
            prefs.hideuserlist = 1;
            mg_userlist_showhide (current_sess, FALSE);
      } else
      {
            prefs.hideuserlist = 0;
            mg_userlist_showhide (current_sess, TRUE);
      }

      gtk_widget_grab_focus (gui->input_box);
}

static void
mg_topic_cb (GtkWidget *entry, gpointer userdata)
{
      session *sess = current_sess;
      char *text;

      if (sess->channel[0] && sess->server->connected)
      {
            text = GTK_ENTRY (entry)->text;
            if (text[0] == 0)
                  text = NULL;
            sess->server->p_topic (sess->server, sess->channel, text);
      } else
            gtk_entry_set_text (GTK_ENTRY (entry), "");
      /* restore focus to the input widget, where the next input will most
likely be */
      gtk_widget_grab_focus (sess->gui->input_box);
}

static void
mg_dcc_cb (GtkDialog *dialog, gint arg1, gpointer userdata)
{
      gtk_widget_destroy (GTK_WIDGET (dialog));
      if (arg1 == GTK_RESPONSE_YES)
            xchat_exit ();
}

static int
mg_dcc_active (void)
{
      GSList *list;
      struct DCC *dcc;

      list = dcc_list;
      while (list)
      {
            dcc = list->data;
            if (dcc->dccstat == STAT_ACTIVE)
                  return 1;
            list = list->next;
      }

      return 0;
}

void
mg_safe_quit (void)
{
      GtkWidget *dialog;

      if (mg_dcc_active ())
      {
            dialog = gtk_message_dialog_new (NULL, 0,
                                                      GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
                                                _("Some file transfers still active, quit xchat?"));
            g_signal_connect (G_OBJECT (dialog), "response",
                                                G_CALLBACK (mg_dcc_cb), NULL);
            gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
            gtk_widget_show (dialog);
      } else
      {
/*          printf("no active DCCs, quiting\n");*/
            xchat_exit ();
      }
}

void
mg_x_click_cb (GtkWidget *button, gpointer userdata)
{
      int page;

      /* this, to handle CTRL-W while in non-irc tab */
      if (current_sess && current_sess->gui->is_tab && mg_gui)
      {
            page = gtk_notebook_get_current_page (GTK_NOTEBOOK (mg_gui->note_book));
            if (page != 0)
            {
                  /* destroy non-irc tab (when called from menu.c) */
                  gtk_widget_destroy (tab_group_get_focused (mg_gui->tabs_box));
                  return;
            }
      }

      /* is it a non-irc tab? */
      if (userdata)
      {
            gtk_widget_destroy (userdata);
            return;
      }

      mg_close_sess (current_sess);
}

static void
mg_changui_destroy (session *sess)
{
      if (sess->gui->is_tab)
      {
            /* avoid calling the "destroy" callback */
            g_signal_handlers_disconnect_by_func (G_OBJECT (sess->res->tab),
                                                                                      mg_tabdestroy_cb, sess);
            tab_remove (sess->res->tab);
            /* any tabs left? */
            if (tab_group_get_size (sess->gui->tabs_box) < 1)
                  /* if not, destroy the main tab window */
                  gtk_widget_destroy (mg_gui->window);
      } else
      {
            /* avoid calling the "destroy" callback */
            g_signal_handlers_disconnect_by_func (G_OBJECT (sess->gui->window),
                                                                                      mg_topdestroy_cb, sess);
            gtk_widget_destroy (sess->gui->window);
            free (sess->gui);
            sess->gui = NULL;
      }
}

static void
mg_link_irctab (session *sess, int focus)
{
      if (sess->gui->is_tab)
      {
            mg_changui_destroy (sess);
            mg_changui_new (sess, sess->res, 0, focus);
            mg_populate (sess);
            xchat_is_quitting = FALSE;
            return;
      }

      mg_unpopulate (sess);
      mg_changui_destroy (sess);
      mg_changui_new (sess, sess->res, 1, focus);
}

static void
mg_link_gentab (GtkWidget *tab)
{
#if 0
      GtkWidget *win, *box, *vbox;

      box = g_object_get_data (G_OBJECT (tab), "box");
      gtk_widget_reparent (box, vbox);
#endif
}

void
mg_link_cb (GtkWidget *but, gpointer userdata)
{
      if (userdata)
      {
            mg_link_gentab (userdata);
            return;
      }

      mg_link_irctab (current_sess, 0);
}

static int
check_is_number (char *t)
{
      while (*t)
      {
            if (*t < '0' || *t > '9')
                  return FALSE;
            t++;
      }
      return TRUE;
}

static void
mg_change_flag (GtkWidget * wid, session *sess, char flag)
{
      server *serv = sess->server;
      char mode[3];

      mode[1] = flag;
      mode[2] = '\0';
      if (serv->connected && sess->channel[0])
      {
            if (GTK_TOGGLE_BUTTON (wid)->active)
                  mode[0] = '+';
            else
                  mode[0] = '-';
            serv->p_mode (serv, sess->channel, mode);
            serv->p_join_info (serv, sess->channel);
            sess->ignore_mode = TRUE;
            sess->ignore_date = TRUE;
      }
}

static void
flagl_hit (GtkWidget * wid, struct session *sess)
{
      char modes[512];
      const char *limit_str;
      server *serv = sess->server;

      if (GTK_TOGGLE_BUTTON (wid)->active)
      {
            if (serv->connected && sess->channel[0])
            {
                  limit_str = gtk_entry_get_text (GTK_ENTRY (sess->gui->limit_entry));
                  if (check_is_number ((char *)limit_str) == FALSE)
                  {
                        gtkutil_simpledialog (_("User limit must be a number!\n"));
                        gtk_entry_set_text (GTK_ENTRY (sess->gui->limit_entry), "");
                        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), FALSE);
                        return;
                  }
                  snprintf (modes, sizeof (modes), "+l %d", atoi (limit_str));
                  serv->p_mode (serv, sess->channel, modes);
                  serv->p_join_info (serv, sess->channel);
            }
      } else
            mg_change_flag (wid, sess, 'l');
}

static void
flagk_hit (GtkWidget * wid, struct session *sess)
{
      char modes[512];
      server *serv = sess->server;

      if (serv->connected && sess->channel[0])
      {
            snprintf (modes, sizeof (modes), "-k %s", 
                    gtk_entry_get_text (GTK_ENTRY (sess->gui->key_entry)));

            if (GTK_TOGGLE_BUTTON (wid)->active)
                  modes[0] = '+';

            serv->p_mode (serv, sess->channel, modes);
      }
}

static void
mg_flagbutton_cb (GtkWidget *but, char *flag)
{
      session *sess;
      char mode;

      if (ignore_chanmode)
            return;

      sess = current_sess;
      mode = tolower (flag[0]);

      switch (mode)
      {
      case 'l':
            flagl_hit (but, sess);
            break;
      case 'k':
            flagk_hit (but, sess);
            break;
      case 'b':
            ignore_chanmode = TRUE;
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess->gui->flag_b), FALSE);
            ignore_chanmode = FALSE;
            banlist_opengui (sess);
            break;
      default:
            mg_change_flag (but, sess, mode);
      }
}

static GtkWidget *
mg_create_flagbutton (char *tip, GtkWidget *box, char *face)
{
      GtkWidget *wid;

      wid = gtk_toggle_button_new_with_label (face);
      gtk_widget_set_size_request (wid, 18, 0);
      add_tip (wid, tip);
      gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
      g_signal_connect (G_OBJECT (wid), "toggled",
                                          G_CALLBACK (mg_flagbutton_cb), face);
      show_and_unfocus (wid);

      return wid;
}

static void
mg_key_entry_cb (GtkWidget * igad, gpointer userdata)
{
      char modes[512];
      session *sess = current_sess;
      server *serv = sess->server;

      if (serv->connected && sess->channel[0])
      {
            snprintf (modes, sizeof (modes), "+k %s",
                        gtk_entry_get_text (GTK_ENTRY (igad)));
            serv->p_mode (serv, sess->channel, modes);
            serv->p_join_info (serv, sess->channel);
      }
}

static void
mg_limit_entry_cb (GtkWidget * igad, gpointer userdata)
{
      char modes[512];
      session *sess = current_sess;
      server *serv = sess->server;

      if (serv->connected && sess->channel[0])
      {
            if (check_is_number ((char *)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_active (GTK_TOGGLE_BUTTON (sess->gui->flag_l), FALSE);
                  return;
            }
            snprintf (modes, sizeof(modes), "+l %d", 
                        atoi (gtk_entry_get_text (GTK_ENTRY (igad))));
            serv->p_mode (serv, sess->channel, modes);
            serv->p_join_info (serv, sess->channel);
      }
}

static void
mg_apply_entry_style (GtkWidget *entry)
{
      gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]);
      gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]);
      gtk_widget_modify_font (entry, input_style->font_desc);
}

static void
mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
{
      gui->flag_t = mg_create_flagbutton (_("Topic Protection"), box, "T");
      gui->flag_n = mg_create_flagbutton (_("No outside messages"), box, "N");
      gui->flag_s = mg_create_flagbutton (_("Secret"), box, "S");
      gui->flag_i = mg_create_flagbutton (_("Invite Only"), box, "I");
      gui->flag_p = mg_create_flagbutton (_("Private"), box, "P");
      gui->flag_m = mg_create_flagbutton (_("Moderated"), box, "M");
      gui->flag_b = mg_create_flagbutton (_("Ban List"), box, "B");

      gui->flag_k = mg_create_flagbutton (_("Keyword"), box, "K");
      gui->key_entry = gtk_entry_new ();
      gtk_widget_set_name (gui->key_entry, "xchat-inputbox");
      gtk_entry_set_max_length (GTK_ENTRY (gui->key_entry), 16);
      gtk_widget_set_size_request (gui->key_entry, 30, -1);
      gtk_box_pack_start (GTK_BOX (box), gui->key_entry, 0, 0, 0);
      g_signal_connect (G_OBJECT (gui->key_entry), "activate",
                                          G_CALLBACK (mg_key_entry_cb), NULL);

      if (prefs.style_inputbox)
            mg_apply_entry_style (gui->key_entry);

      gui->flag_l = mg_create_flagbutton (_("User Limit"), box, "L");
      gui->limit_entry = gtk_entry_new ();
      gtk_widget_set_name (gui->limit_entry, "xchat-inputbox");
      gtk_entry_set_max_length (GTK_ENTRY (gui->limit_entry), 10);
      gtk_widget_set_size_request (gui->limit_entry, 30, -1);
      gtk_box_pack_start (GTK_BOX (box), gui->limit_entry, 0, 0, 0);
      g_signal_connect (G_OBJECT (gui->limit_entry), "activate",
                                          G_CALLBACK (mg_limit_entry_cb), NULL);

      if (prefs.style_inputbox)
            mg_apply_entry_style (gui->limit_entry);
}

static void
mg_create_link_buttons (GtkWidget *box, gpointer userdata)
{
      gtkutil_button (box, GTK_STOCK_CLOSE, _("Close this tab/window"),
                                     mg_x_click_cb, userdata, 0);

      /*if (!userdata)
      gtkutil_button (box, GTK_STOCK_REDO, _("Attach/Detach this tab"),
                                     mg_link_cb, userdata, 0);*/
}

static void
mg_dialog_button_cb (GtkWidget *wid, char *cmd)
{
      /* the longest cmd is 12, and the longest nickname is 64 */
      char buf[128];
      char *host = "";
      char *topic;

      if (!current_sess)
            return;

      topic = (char *)(GTK_ENTRY (current_sess->gui->topic_entry)->text);
      topic = strrchr (topic, '@');
      if (topic)
            host = topic + 1;

      auto_insert (buf, sizeof (buf), cmd, 0, 0, "", "", "", host, "", current_sess->channel);

      handle_command (current_sess, buf, TRUE);

      /* dirty trick to avoid auto-selection */
      GTK_ENTRY (current_sess->gui->input_box)->editable = 0;
      gtk_widget_grab_focus (current_sess->gui->input_box);
      GTK_ENTRY (current_sess->gui->input_box)->editable = 1;
}

static void
mg_dialog_button (GtkWidget *box, char *name, char *cmd)
{
      GtkWidget *wid;

      wid = gtk_button_new_with_label (name);
      gtk_box_pack_start (GTK_BOX (box), wid, FALSE, FALSE, 0);
      g_signal_connect (G_OBJECT (wid), "clicked",
                                          G_CALLBACK (mg_dialog_button_cb), cmd);
      gtk_widget_set_size_request (wid, -1, 0);
}

static void
mg_create_dialogbuttons (GtkWidget *box)
{
      struct popup *pop;
      GSList *list = dlgbutton_list;

      while (list)
      {
            pop = list->data;
            if (pop->cmd[0])
                  mg_dialog_button (box, pop->name, pop->cmd);
            list = list->next;
      }
}

static void
mg_create_topicbar (session *sess, GtkWidget *box, char *name)
{
      GtkWidget *hbox, *topic, *bbox;
      session_gui *gui = sess->gui;

      gui->topic_bar = hbox = gtk_hbox_new (FALSE, 1);
      gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0);

      mg_create_link_buttons (hbox, NULL);

      if (!gui->is_tab)
      {
            sess->res->tab = gtk_toggle_button_new_with_label (name);
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess->res->tab), TRUE);
            gtk_box_pack_start (GTK_BOX (hbox), sess->res->tab, 0, 0, 0);
      }

      gui->topic_entry = topic = gtk_entry_new ();
      gtk_widget_set_name (topic, "xchat-inputbox");
      gtk_container_add (GTK_CONTAINER (hbox), topic);
      g_signal_connect (G_OBJECT (topic), "activate",
                                          G_CALLBACK (mg_topic_cb), 0);

      if (prefs.style_inputbox)
            mg_apply_entry_style (topic);

      gui->topicbutton_box = bbox = gtk_hbox_new (FALSE, 0);
      gtk_box_pack_start (GTK_BOX (hbox), bbox, 0, 0, 0);
      mg_create_chanmodebuttons (gui, bbox);

      gui->dialogbutton_box = bbox = gtk_hbox_new (FALSE, 0);
      gtk_box_pack_start (GTK_BOX (hbox), bbox, 0, 0, 0);
      mg_create_dialogbuttons (bbox);

      if (!prefs.paned_userlist)
            gtkutil_button (hbox, GTK_STOCK_GOTO_LAST, _("Show/Hide userlist"),
                                           mg_userlist_toggle_cb, 0, 0);
}

/* check if a word is clickable */

static int
mg_word_check (GtkWidget * xtext, char *word)
{
      return text_word_check (word);      /* common/text.c */
}

/* mouse click inside text area */

static void
mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even,
                                session *sess)
{
      sess = current_sess;

      if (even->button == 1)              /* left button */
      {
            if (word == NULL)
            {
                  mg_focus (sess);
                  return;
            }

            if (even->state & GDK_CONTROL_MASK)
            {
                  switch (mg_word_check (xtext, word))
                  {
                  case WORD_URL:
                  case WORD_HOST:
                        goto_url (word);
                  }
            }
            return;
      }

      if (even->button == 2)
      {
            if (sess->type == SESS_DIALOG)
                  menu_middlemenu (sess, even);
            else if (even->type == GDK_2BUTTON_PRESS)
                  userlist_select (sess, word);
            return;
      }

      switch (mg_word_check (xtext, word))
      {
      case 0:
            menu_middlemenu (sess, even);
            break;
      case WORD_URL:
      case WORD_HOST:
            menu_urlmenu (even, word);
            break;
      case WORD_NICK:
            menu_nickmenu (sess, even, (word[0]=='@' || word[0]=='+') ?
                  word+1 : word, FALSE);
            break;
      case WORD_CHANNEL:
            if (*word == '@' || *word == '+' || *word=='^' || *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 (even, newword);
                  free (newword);
            }
            break;
      case WORD_DIALOG:
            menu_nickmenu (sess, even, sess->channel, FALSE);
            break;
      }
}

void
mg_update_xtext (GtkWidget *wid)
{
      GtkXText *xtext = GTK_XTEXT (wid);

      gtk_xtext_set_palette (xtext, colors);
      gtk_xtext_set_max_lines (xtext, prefs.max_lines);
      gtk_xtext_set_tint (xtext, prefs.tint_red, prefs.tint_green, prefs.tint_blue);
      gtk_xtext_set_background (xtext, channelwin_pix, prefs.transparent, prefs.tint);
      gtk_xtext_set_wordwrap (xtext, prefs.wordwrap);
      gtk_xtext_set_show_marker (xtext, prefs.show_marker);
      gtk_xtext_set_show_separator (xtext, prefs.indent_nicks ? prefs.show_separator : 0);
      gtk_xtext_set_indent (xtext, prefs.indent_nicks);
      if (!gtk_xtext_set_font (xtext, prefs.font_normal))
      {
            fe_message ("Failed to open any font. I'm out of here!", TRUE);
            exit (1);
      }

      gtk_xtext_refresh (xtext, FALSE);
}

/* handle errors reported by xtext */

static void
mg_xtext_error (int type)
{
      switch (type)
      {
      case 0:
            gtkutil_simpledialog (_("Unable to set transparent background!\n\n"
                                                            "You may be using a non-compliant window\n"
                                                            "manager that is not currently supported.\n"));
            prefs.transparent = 0;
            /* no others exist yet */
      }
}

static void
mg_create_textarea (session_gui *gui, GtkWidget *box)
{
      GtkWidget *inbox, *hbox, *frame;
      GtkXText *xtext;

      hbox = gtk_vbox_new (FALSE, 1);
      gtk_container_add (GTK_CONTAINER (box), hbox);

      inbox = gtk_hbox_new (FALSE, 1);
      gtk_container_add (GTK_CONTAINER (hbox), inbox);

      frame = gtk_frame_new (NULL);
      gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
      gtk_container_add (GTK_CONTAINER (inbox), frame);

      gui->xtext = gtk_xtext_new (colors, TRUE);
      xtext = GTK_XTEXT (gui->xtext);
      gtk_xtext_set_max_indent (xtext, prefs.max_auto_indent);
      gtk_xtext_set_thin_separator (xtext, prefs.thin_separator);
      gtk_xtext_set_error_function (xtext, mg_xtext_error);
      gtk_xtext_set_urlcheck_function (xtext, mg_word_check);
      gtk_xtext_set_max_lines (xtext, prefs.max_lines);
      gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (xtext));
      mg_update_xtext (GTK_WIDGET (xtext));

      g_signal_connect (G_OBJECT (xtext), "word_click",
                                          G_CALLBACK (mg_word_clicked), NULL);

      gui->vscrollbar = gtk_vscrollbar_new (GTK_XTEXT (xtext)->adj);
      gtk_box_pack_start (GTK_BOX (inbox), gui->vscrollbar, FALSE, TRUE, 1);
}

static GtkWidget *
mg_create_infoframe (GtkWidget *box)
{
      GtkWidget *frame, *label, *hbox;

      frame = gtk_frame_new (0);
      gtk_frame_set_shadow_type ((GtkFrame*)frame, GTK_SHADOW_OUT);
      gtk_container_add (GTK_CONTAINER (box), frame);

      hbox = gtk_hbox_new (0, 0);
      gtk_container_add (GTK_CONTAINER (frame), hbox);

      label = gtk_label_new (NULL);
      gtk_container_add (GTK_CONTAINER (hbox), label);

      return label;
}

static void
mg_create_meters (session_gui *gui, GtkWidget *box)
{
      GtkWidget *infbox = box, *wid;

      if ((prefs.lagometer & 2) || (prefs.throttlemeter & 2))
      {
            infbox = gtk_hbox_new (0, 0);
            gtk_box_pack_start (GTK_BOX (box), infbox, 0, 0, 0);
      }

      if (prefs.lagometer & 1)
      {
            gui->lagometer = wid = gtk_progress_bar_new ();
            gtk_widget_set_size_request (wid, 1, 8);
            gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
      }
      if (prefs.lagometer & 2)
      {
            gui->laginfo = wid = mg_create_infoframe (infbox);
            gtk_label_set_text ((GtkLabel *) wid, "Lag");
      }

      if (prefs.throttlemeter & 1)
      {
            gui->throttlemeter = wid = gtk_progress_bar_new ();
            gtk_widget_set_size_request (wid, 1, 8);
            gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
      }
      if (prefs.throttlemeter & 2)
      {
            gui->throttleinfo = wid = mg_create_infoframe (infbox);
            gtk_label_set_text ((GtkLabel *) wid, "Throttle");
      }
}

static void
mg_create_userlist (session_gui *gui, GtkWidget *box, int pack)
{
      GtkWidget *frame, *ulist, *vbox;

      vbox = gtk_vbox_new (0, 2);
      if (pack)
            gtk_box_pack_start (GTK_BOX (box), vbox, 0, 0, 0);
      else
            gtk_container_add (GTK_CONTAINER (box), vbox);

      frame = gtk_frame_new (NULL);
      gtk_box_pack_start (GTK_BOX (vbox), frame, 0, 0, 0);

      gui->namelistinfo = gtk_label_new (NULL);
      gtk_container_add (GTK_CONTAINER (frame), gui->namelistinfo);

      gui->user_box = vbox;

      gui->user_tree = ulist = userlist_create (vbox);
      gtk_widget_set_size_request (ulist, 86, -1);

      if (prefs.style_namelistgad)
      {
            gtk_widget_set_style (ulist, input_style);
            gtk_widget_modify_base (ulist, GTK_STATE_NORMAL, &colors[COL_BG]);
      }

      mg_create_meters (gui, vbox);

      gui->button_box_parent = vbox;
      gui->button_box = mg_create_userlistbuttons (vbox);
}

static void
mg_create_center (session *sess, session_gui *gui, GtkWidget *box)
{
      GtkWidget *vbox, *hbox, *paned;

      hbox = gtk_hbox_new (FALSE, 3);

      if (prefs.paned_userlist)
      {
            gui->pane = paned = gtk_hpaned_new ();
            gtk_paned_pack1 (GTK_PANED (paned), hbox, TRUE, TRUE);

            vbox = gtk_vbox_new (FALSE, 1);
            gtk_container_add (GTK_CONTAINER (hbox), vbox);
            mg_create_topicbar (sess, vbox, NULL);

            gtk_container_add (GTK_CONTAINER (box), paned);

            mg_create_textarea (gui, vbox);
            mg_create_entry (sess, vbox);

            hbox = gtk_hbox_new (FALSE, 1);
            gtk_paned_pack2 (GTK_PANED (paned), hbox, FALSE, TRUE);

            mg_create_userlist (gui, hbox, FALSE);

            if (gui->pane)
            {
                  if (gui->pane_pos == 0)
                        gui->pane_pos = prefs.paned_pos;
                  if (gui->pane_pos == 0)
                        gui->pane_pos = prefs.mainwindow_width - 140;
                  gtk_paned_set_position (GTK_PANED (gui->pane), gui->pane_pos);
            }

      } else
      {
            gtk_container_add (GTK_CONTAINER (box), hbox);

            vbox = gtk_vbox_new (FALSE, 1);
            gtk_container_add (GTK_CONTAINER (hbox), vbox);
            mg_create_topicbar (sess, vbox, NULL);

            mg_create_textarea (gui, vbox);
            mg_create_userlist (gui, hbox, TRUE);
            mg_create_entry (sess, vbox);
      }
}

static void
mg_change_nick (int cancel, char *text, gpointer userdata)
{
      char buf[256];

      if (!cancel)
      {
            snprintf (buf, sizeof (buf), "nick %s", text);
            handle_command (current_sess, buf, FALSE);
      }
}

static void
mg_nickclick_cb (GtkWidget *button, gpointer userdata)
{
      fe_get_str (_("Enter new nickname:"), current_sess->server->nick,
                              mg_change_nick, NULL);
}

static void
mg_set_tabs_pos (session_gui *gui, int pos)
{
      GtkOrientation orientation;
      GtkWidget *new_tabs_box;

      if (!gui)
      {
            gui = mg_gui;
            if (!gui)
                  return;
      }

      gtk_widget_ref (gui->tabs_box);

      if (pos != 4)
            gtk_container_remove (GTK_CONTAINER (gui->main_table), gui->tabs_box);

      orientation = tab_group_get_orientation (gui->tabs_box);
      if ((pos == 0 || pos == 1) && orientation == GTK_ORIENTATION_VERTICAL)
      {
            new_tabs_box = tab_group_set_orientation (gui->tabs_box, FALSE);
            gtk_widget_unref (gui->tabs_box);
            gui->tabs_box = new_tabs_box;
      } else if((pos == 2 || pos == 3) && orientation == GTK_ORIENTATION_HORIZONTAL) {
            new_tabs_box = tab_group_set_orientation (gui->tabs_box, TRUE);
            gtk_widget_unref (gui->tabs_box);
            gui->tabs_box = new_tabs_box;
      }

      gtk_widget_show (gui->tabs_box);

      switch (pos)
      {
      case 0: /* bottom */
            gtk_table_attach (GTK_TABLE (gui->main_table), gui->tabs_box,
                                          1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
            break;
      case 1: /* top */
            gtk_table_attach (GTK_TABLE (gui->main_table), gui->tabs_box,
                                          1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
            break;
      case 2: /* left */
            gtk_table_attach (GTK_TABLE (gui->main_table), gui->tabs_box,
                                          0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
            break;
      case 3: /* right */
            gtk_table_attach (GTK_TABLE (gui->main_table), gui->tabs_box,
                                          2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
            break;
      case 4: /* hidden */
            gtk_widget_hide (gui->tabs_box);
            break;
      }

      if (orientation == tab_group_get_orientation (gui->tabs_box))
            gtk_widget_unref (gui->tabs_box);
}

static void
mg_create_entry (session *sess, GtkWidget *box)
{
      GtkWidget *hbox, *but, *entry;
      session_gui *gui = sess->gui;

      hbox = gtk_hbox_new (FALSE, 0);
      gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0);

      gui->nick_box = gtk_hbox_new (FALSE, 0);
      gtk_box_pack_start (GTK_BOX (hbox), gui->nick_box, 0, 0, 0);

      gui->nick_label = but = gtk_button_new_with_label (sess->server->nick);
      gtk_button_set_relief (GTK_BUTTON (but), GTK_RELIEF_NONE);
      GTK_WIDGET_UNSET_FLAGS (but, GTK_CAN_FOCUS);
      gtk_box_pack_end (GTK_BOX (gui->nick_box), but, 0, 0, 0);
      g_signal_connect (G_OBJECT (but), "clicked",
                                          G_CALLBACK (mg_nickclick_cb), NULL);

      gui->input_box = entry = gtk_entry_new ();
      gtk_widget_set_name (entry, "xchat-inputbox");
      gtk_entry_set_max_length (GTK_ENTRY (gui->input_box), 2048);
      g_signal_connect (G_OBJECT (entry), "key_press_event",
                                          G_CALLBACK (key_handle_key_press), NULL);
      g_signal_connect (G_OBJECT (entry), "focus_in_event",
                                          G_CALLBACK (mg_inputbox_focus), gui);
      g_signal_connect (G_OBJECT (entry), "activate",
                                          G_CALLBACK (mg_inputbox_cb), gui);
      gtk_container_add (GTK_CONTAINER (hbox), entry);
      gtk_widget_grab_focus (entry);

      if (prefs.style_inputbox)
            mg_apply_entry_style (entry);
}

static void
mg_switch_tab_cb (GtkWidget *tab, session *sess, gpointer family)
{
      GtkWidget *old;

      old = active_tab;
      active_tab = GTK_WIDGET (tab);

      /* sess of NULL is reserved for non-irc tabs */
      if (sess)
      {
            if (active_tab != old)
            {
                  if (old && current_tab)
                        mg_unpopulate (current_tab);
                  mg_populate (sess);
            }
      } else if (old != active_tab)
            mg_show_generic_tab (active_tab);
}

/* compare two tabs (for tab sorting function) */

static int
mg_tabs_compare (session *a, session *b)
{
      /* this is for "Open Utilities in: Tabs" (i.e. sess is NULL) */
      if (!a)
            return 1;
      if (!b)
            return -1;

      /* server tabs always go first */
      if (a->type == SESS_SERVER)
            return -1;

      /* then channels */
      if (a->type == SESS_CHANNEL && b->type != SESS_CHANNEL)
            return -1;
      if (a->type != SESS_CHANNEL && b->type == SESS_CHANNEL)
            return 1;

      return strcasecmp (a->channel, b->channel);
}

static void
mg_create_tabs (session_gui *gui, GtkWidget *box)
{
      gboolean vert = FALSE;

      if (prefs.tabs_position == 2 || prefs.tabs_position == 3)
            vert = TRUE;

      gui->tabs_box = tab_group_new (mg_switch_tab_cb, mg_tabs_compare,
                                                                   vert, prefs.tab_sort);
      gtk_table_attach (GTK_TABLE (gui->main_table), gui->tabs_box,
                                    1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
}

static gboolean
mg_tabwin_focus_cb (GtkWindow * win, GdkEventFocus *event, gpointer userdata)
{
      current_sess = current_tab;
      if (current_sess)
      {
            gtk_xtext_check_marker_visibility (GTK_XTEXT (current_sess->gui->xtext));
            plugin_emit_dummy_print (current_sess, "Focus Window");
      }
      return FALSE;
}

static gboolean
mg_topwin_focus_cb (GtkWindow * win, GdkEventFocus *event, session *sess)
{
      current_sess = sess;
      if (!sess->server->server_session)
            sess->server->server_session = sess;
      gtk_xtext_check_marker_visibility(GTK_XTEXT (current_sess->gui->xtext));
      plugin_emit_dummy_print (sess, "Focus Window");
      return FALSE;
}

static void
mg_create_menu (session_gui *gui, GtkWidget *box, int away_state)
{
      GtkAccelGroup *accel_group;

      accel_group = gtk_accel_group_new ();
      gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel (box)),
                                                             accel_group);
      g_object_unref (accel_group);

      gui->menu = menu_create_main (accel_group, TRUE, away_state, !gui->is_tab,
                                                                  &gui->away_item, &gui->user_menu);
      gtk_box_pack_start (GTK_BOX (box), gui->menu, 0, 0, 0);
      gtk_box_reorder_child (GTK_BOX (box), gui->menu, 0);
}

static void
mg_create_topwindow (session *sess)
{
      GtkWidget *win;
      GtkWidget *vbox;
      GtkWidget *vvbox;

      if (sess->type == SESS_DIALOG)
            win = gtkutil_window_new ("X-Chat ["VERSION"]", NULL,
                                                              prefs.dialog_width, prefs.dialog_height, 0);
      else
            win = gtkutil_window_new ("X-Chat ["VERSION"]", NULL,
                                                              prefs.mainwindow_width,
                                                              prefs.mainwindow_height, 0);
      sess->gui->window = win;
      gtk_container_set_border_width (GTK_CONTAINER (win), 2);
      g_signal_connect (G_OBJECT (win), "focus_in_event",
                                          G_CALLBACK (mg_topwin_focus_cb), sess);
      g_signal_connect (G_OBJECT (win), "destroy",
                                          G_CALLBACK (mg_topdestroy_cb), sess);
      g_signal_connect (G_OBJECT (win), "configure_event",
                                          G_CALLBACK (mg_configure_cb), sess);

      palette_alloc (win);

      vbox = gtk_vbox_new (FALSE, 1);
      gtk_container_add (GTK_CONTAINER (win), vbox);

      vvbox = gtk_vbox_new (FALSE, 3);
      gtk_container_add (GTK_CONTAINER (vbox), vvbox);

      mg_create_center (sess, sess->gui, vvbox);
      mg_create_menu (sess->gui, vbox, sess->server->is_away);

      if (sess->res->buffer == NULL)
      {
            sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext));
            gtk_xtext_buffer_show (GTK_XTEXT (sess->gui->xtext), sess->res->buffer, TRUE);
            gtk_xtext_set_time_stamp (sess->res->buffer, prefs.timestamp);
            sess->res->user_model = userlist_create_model ();
      }

      userlist_show (sess);

      gtk_widget_show_all (win);

      if (prefs.hidemenu)
            gtk_widget_hide (sess->gui->menu);

      if (sess->type == SESS_DIALOG)
      {
            /* hide the chan-mode buttons */
            gtk_widget_hide (sess->gui->topicbutton_box);
            /* hide the userlist */
            mg_userlist_showhide (sess, FALSE);
      } else
      {
            gtk_widget_hide (sess->gui->dialogbutton_box);

            if (prefs.hideuserlist)
                  mg_userlist_showhide (sess, FALSE);

            if (!prefs.chanmodebuttons)
                  gtk_widget_hide (sess->gui->topicbutton_box);
      }

      if (!prefs.userlistbuttons)
            gtk_widget_hide (sess->gui->button_box);

      if (!prefs.topicbar)
            gtk_widget_hide (sess->gui->topic_bar);
}

static void
mg_create_irctab (session *sess, GtkWidget *book)
{
      GtkWidget *vbox;
      session_gui *gui = sess->gui;

      vbox = gtk_vbox_new (FALSE, 3);
      gtk_notebook_append_page (GTK_NOTEBOOK (book), vbox, NULL);

      mg_create_center (sess, gui, vbox);
}

static void
mg_tabwindow_kill_cb (GtkWidget *win, gpointer userdata)
{
      GSList *list;
      session *sess;

/*    puts("enter mg_tabwindow_kill_cb");*/
      xchat_is_quitting = TRUE;

      /* see if there's any non-tab windows left */
      list = sess_list;
      while (list)
      {
            sess = list->data;
            if (!sess->gui->is_tab)
            {
                  xchat_is_quitting = FALSE;
/*                puts("-> will not exit, some toplevel windows left");*/
                  break;
            }
            list = list->next;
      }

      current_tab = NULL;
      active_tab = NULL;
      mg_gui = NULL;
      parent_window = NULL;
}

static gboolean
mg_tabwindow_de_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
      GSList *list;
      session *sess;

      /* check for remaining toplevel windows */
      list = sess_list;
      while (list)
      {
            sess = list->data;
            if (!sess->gui->is_tab)
            {
/*                printf("toplevel's remain, not quiting\n");*/
                  return FALSE;
            }
            list = list->next;
      }

      mg_safe_quit ();
      return TRUE;
}

static void
mg_create_tabwindow (session *sess)
{
      GtkWidget *win;
      GtkWidget *vbox;
      GtkWidget *table;
      GtkWidget *book;

      win = gtkutil_window_new ("X-Chat ["VERSION"]", NULL, prefs.mainwindow_width,
                                                        prefs.mainwindow_height, 0);
      sess->gui->window = win;
      gtk_window_move (GTK_WINDOW (win), prefs.mainwindow_left,
                                      prefs.mainwindow_top);
      if (prefs.gui_win_state)
            gtk_window_maximize (GTK_WINDOW (win));
      gtk_container_set_border_width (GTK_CONTAINER (win), 2);

      g_signal_connect (G_OBJECT (win), "delete_event",
                                       G_CALLBACK (mg_tabwindow_de_cb), 0);
      g_signal_connect (G_OBJECT (win), "destroy",
                                       G_CALLBACK (mg_tabwindow_kill_cb), 0);
      g_signal_connect (G_OBJECT (win), "focus_in_event",
                                          G_CALLBACK (mg_tabwin_focus_cb), NULL);
      g_signal_connect (G_OBJECT (win), "configure_event",
                                          G_CALLBACK (mg_configure_cb), NULL);
      g_signal_connect (G_OBJECT (win), "window_state_event",
                                          G_CALLBACK (mg_windowstate_cb), NULL);

      palette_alloc (win);

      sess->gui->main_vbox = vbox = gtk_vbox_new (FALSE, 1);
      gtk_container_add (GTK_CONTAINER (win), vbox);

      sess->gui->main_table = table = gtk_table_new (3, 3, FALSE);
      gtk_container_add (GTK_CONTAINER (vbox), table);

      sess->gui->note_book = book = gtk_notebook_new ();
      gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE);
      gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE);
      gtk_table_attach (GTK_TABLE (table), book, 1, 2, 1, 2,
                                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);

      mg_create_irctab (sess, book);
      mg_create_tabs (sess->gui, vbox);
      mg_create_menu (sess->gui, vbox, sess->server->is_away);

      mg_focus (sess);

      if (prefs.tabs_position != 1)
            mg_set_tabs_pos (sess->gui, prefs.tabs_position);

      if (!prefs.hidemenu)
            gtk_widget_show (sess->gui->menu);

      gtk_widget_show (vbox);
      gtk_widget_show (table);
      gtk_widget_show_all (book);

      if (prefs.hideuserlist)
            mg_userlist_showhide (sess, FALSE);

      if (!prefs.topicbar)
            gtk_widget_hide (sess->gui->topic_bar);

      if (!prefs.chanmodebuttons)
            gtk_widget_hide (sess->gui->topicbutton_box);

      if (!prefs.userlistbuttons)
            gtk_widget_hide (sess->gui->button_box);

      gtk_widget_show (win);
}

void
mg_apply_setup (void)
{
      GSList *list = sess_list;
      session *sess;

      mg_create_tab_colors ();

      while (list)
      {
            sess = list->data;
            gtk_xtext_set_time_stamp (sess->res->buffer, prefs.timestamp);
            ((xtext_buffer *)sess->res->buffer)->needs_recalc = TRUE;
            list = list->next;
      }

      if (mg_gui)
            mg_set_tabs_pos (mg_gui, prefs.tabs_position);
}

static GtkWidget *
mg_add_generic_tab (char *name, char *title, void *family, GtkWidget *box)
{
      GtkWidget *but;

      gtk_notebook_append_page (GTK_NOTEBOOK (mg_gui->note_book), box, NULL);
      gtk_widget_show (box);

      but = tab_group_add (mg_gui->tabs_box, name, family, NULL,
                                                mg_tab_press_cb, mg_link_cb, prefs.truncchans,
                                                prefs.tab_dnd);
      tab_set_attrlist (but, plain_list);
      g_object_set_data (G_OBJECT (but), "title", strdup (title));
      g_object_set_data (G_OBJECT (but), "box", box);
      g_object_set_data (G_OBJECT (but), "sess", NULL);

      g_signal_connect (G_OBJECT (but), "destroy",
                                    G_CALLBACK (mg_tabdestroy_cb), 0);

      if (prefs.newtabstofront)
            tab_focus (but);

      return but;
}

void
fe_buttons_update (session *sess)
{
      session_gui *gui = sess->gui;

      gtk_widget_destroy (gui->button_box);
      gui->button_box = mg_create_userlistbuttons (gui->button_box_parent);

      if (prefs.userlistbuttons)
            gtk_widget_show (sess->gui->button_box);
      else
            gtk_widget_hide (sess->gui->button_box);
}

void
fe_clear_channel (session *sess)
{
      char tbuf[CHANLEN+6];
      session_gui *gui = sess->gui;

      if (sess->waitchannel[0])
      {
            if (prefs.truncchans > 2 && g_utf8_strlen (sess->waitchannel, -1) > prefs.truncchans)
            {
                  /* truncate long channel names */
                  tbuf[0] = '(';
                  strcpy (tbuf + 1, sess->waitchannel);
                  g_utf8_offset_to_pointer(tbuf, prefs.truncchans)[0] = 0;
                  strcat (tbuf, "..)");
            } else
            {
                  sprintf (tbuf, "(%s)", sess->waitchannel);
            }
      }
      else
            strcpy (tbuf, _("<none>"));
      tab_rename (sess->res->tab, tbuf, prefs.truncchans);

      if (!sess->gui->is_tab || sess == current_tab)
      {
            gtk_entry_set_text (GTK_ENTRY (gui->topic_entry), "");

            if (gui->op_xpm)
            {
                  gtk_widget_destroy (gui->op_xpm);
                  gui->op_xpm = 0;
            }
      } else
      {
            if (sess->res->topic_text)
            {
                  free (sess->res->topic_text);
                  sess->res->topic_text = NULL;
            }
      }
}

void
fe_set_nonchannel (session *sess, int state)
{
}

void
fe_dlgbuttons_update (session *sess)
{
      GtkWidget *box;
      session_gui *gui = sess->gui;

      gtk_widget_destroy (gui->dialogbutton_box);

      gui->dialogbutton_box = box = gtk_hbox_new (0, 0);
      gtk_box_pack_start (GTK_BOX (gui->topic_bar), box, 0, 0, 0);
      gtk_box_reorder_child (GTK_BOX (gui->topic_bar), box, 3);
      mg_create_dialogbuttons (box);

      gtk_widget_show_all (box);

      if (current_tab && current_tab->type != SESS_DIALOG)
            gtk_widget_hide (current_tab->gui->dialogbutton_box);
}

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

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

      for (i = 0; i < NUM_FLAG_WIDS - 1; i++)
      {
            if (chan_flags[i] == mode)
            {
                  if (!sess->gui->is_tab || sess == current_tab)
                  {
                        ignore_chanmode = TRUE;
                        if (GTK_TOGGLE_BUTTON (sess->gui->flag_wid[i])->active != state)
                              gtk_toggle_button_set_active (
                                          GTK_TOGGLE_BUTTON (sess->gui->flag_wid[i]), state);
                        ignore_chanmode = FALSE;
                  } else
                  {
                        sess->res->flag_wid_state[i] = state;
                  }
                  return;
            }
      }
}

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

      while (list)
      {
            sess = list->data;
            if (sess->server == serv)
            {
                  if (current_tab == sess || !sess->gui->is_tab)
                        gtk_button_set_label (GTK_BUTTON (sess->gui->nick_label), newnick);
            }
            list = list->next;
      }
}

void
fe_set_away (server *serv)
{
      GSList *list = sess_list;
      session *sess;

      while (list)
      {
            sess = list->data;
            if (sess->server == serv)
            {
                  if (!sess->gui->is_tab || sess == current_tab)
                        GTK_CHECK_MENU_ITEM (sess->gui->away_item)->active = serv->is_away;
            }
            list = list->next;
      }
}

void
fe_set_channel (session *sess)
{
      tab_rename (sess->res->tab, sess->channel, prefs.truncchans);
}

void
mg_changui_new (session *sess, restore_gui *res, int tab, int focus)
{
      int first_run = FALSE;
      session_gui *gui;
      struct User *user = NULL;

      if (!res)
      {
            res = malloc (sizeof (restore_gui));
            memset (res, 0, sizeof (restore_gui));
      }

      sess->res = res;

      if (!sess->server->front_session)
            sess->server->front_session = sess;

      if (!is_channel (sess->server, sess->channel))
            user = find_name_global (sess->server, sess->channel);

      if (!tab)
      {
            gui = malloc (sizeof (session_gui));
            memset (gui, 0, sizeof (session_gui));
            gui->is_tab = FALSE;
            sess->gui = gui;
            mg_create_topwindow (sess);
            fe_set_title (sess);
            if (user && user->hostname)
                  set_topic (sess, user->hostname);
            return;
      }

      if (mg_gui == NULL)
      {
            first_run = TRUE;
            gui = &static_mg_gui;
            memset (gui, 0, sizeof (session_gui));
            gui->is_tab = TRUE;
            sess->gui = gui;
            mg_create_tabwindow (sess);
            mg_gui = gui;
            parent_window = gui->window;
      } else
      {
            sess->gui = gui = mg_gui;
            gui->is_tab = TRUE;
      }

      if (user && user->hostname)
            set_topic (sess, user->hostname);

      mg_add_chan (sess);

      if (first_run || (prefs.newtabstofront == FOCUS_NEW_ONLY_ASKED && focus)
                  || prefs.newtabstofront == FOCUS_NEW_ALL )
            tab_focus (res->tab);

/*    while (g_main_pending ())
            g_main_iteration (TRUE);*/
      /*g_idle_add ((GSourceFunc)tab_group_resize, mg_gui->tabs_box);*/
}

GtkWidget *
mg_create_generic_tab (char *name, char *title, int force_toplevel,
                                            int link_buttons,
                                            void *close_callback, void *userdata,
                                            int width, int height, GtkWidget **vbox_ret,
                                            void *family)
{
      GtkWidget *tab, *vbox, *hbox, *win;

      if (force_toplevel || !prefs.windows_as_tabs)
      {
            win = gtkutil_window_new (title, name, width, height, 3);
            vbox = gtk_vbox_new (0, 0);
            *vbox_ret = vbox;
            gtk_container_add (GTK_CONTAINER (win), vbox);
            gtk_widget_show (vbox);
            if (close_callback)
                  g_signal_connect (G_OBJECT (win), "destroy",
                                                      G_CALLBACK (close_callback), userdata);
            g_object_set_data (G_OBJECT (win), "box", vbox);
            return win;
      }

      vbox = gtk_vbox_new (0, 0);
      *vbox_ret = vbox;

      if (close_callback)
            g_signal_connect (G_OBJECT (vbox), "destroy",
                                                G_CALLBACK (close_callback), userdata);

      tab = mg_add_generic_tab (name, title, family, vbox);

      if (link_buttons)
      {
            hbox = gtk_hbox_new (FALSE, 0);
            gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 0);
            mg_create_link_buttons (hbox, tab);
            gtk_widget_show (hbox);
      }

      return tab;
}

void
mg_topic_showhide (session *sess)
{
      if (GTK_WIDGET_VISIBLE (sess->gui->topic_bar))
      {
            gtk_widget_hide (sess->gui->topic_bar);
            prefs.topicbar = 0;
      } else
      {
            gtk_widget_show (sess->gui->topic_bar);
            prefs.topicbar = 1;
      }
}

void
mg_move_tab (GtkWidget *button, int delta)
{
      tab_move (button, delta);
}

void
mg_move_tab_family (GtkWidget *button, int delta)
{
      tab_family_move (button, delta);
}

void
mg_set_title (GtkWidget *button, char *title)
{
      char *old;

      old = g_object_get_data (G_OBJECT (button), "title");
      g_object_set_data (G_OBJECT (button), "title", strdup (title));
      if (old)
            free (old);
}

void
fe_server_callback (server *serv)
{
      if (serv->gui->chanlist_window)
            gtk_widget_destroy (serv->gui->chanlist_window);

      if (serv->gui->rawlog_window)
            gtk_widget_destroy (serv->gui->rawlog_window);

      free (serv->gui);
}

/* called when a session is being killed */

void
fe_session_callback (session *sess)
{
      if (sess->res->input_text)
            free (sess->res->input_text);

      if (sess->res->topic_text)
            free (sess->res->topic_text);

      if (sess->res->limit_text)
            free (sess->res->limit_text);

      if (sess->res->key_text)
            free (sess->res->key_text);

      if (sess->res->queue_text)
            free (sess->res->queue_text);

      if (sess->res->lag_text)
            free (sess->res->lag_text);

      if (sess->gui->bartag)
            fe_timeout_remove (sess->gui->bartag);

      if (sess->gui != mg_gui)
            free (sess->gui);
      free (sess->res);
}

Generated by  Doxygen 1.6.0   Back to index