2 * Copyright (C) 1998-2005 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
24 #include <gtk/gtkarrow.h>
25 #include <gtk/gtktogglebutton.h>
26 #include <gtk/gtkhbox.h>
27 #include <gtk/gtkvbox.h>
28 #include <gtk/gtkeventbox.h>
29 #include <gtk/gtkentry.h>
30 #include <gtk/gtkhpaned.h>
31 #include <gtk/gtkvpaned.h>
32 #include <gtk/gtkframe.h>
33 #include <gtk/gtklabel.h>
34 #include <gtk/gtkmenuitem.h>
35 #include <gtk/gtkprogressbar.h>
36 #include <gtk/gtkscrolledwindow.h>
37 #include <gtk/gtkstock.h>
38 #include <gtk/gtktable.h>
39 #include <gtk/gtknotebook.h>
40 #include <gtk/gtkimage.h>
41 #include <gtk/gtkmessagedialog.h>
42 #include <gtk/gtkcheckmenuitem.h>
43 #include <gtk/gtkcheckbutton.h>
44 #include <gtk/gtkbbox.h>
45 #include <gtk/gtkvscrollbar.h>
47 #include "../common/xchat.h"
48 #include "../common/fe.h"
49 #include "../common/server.h"
50 #include "../common/xchatc.h"
51 #include "../common/outbound.h"
52 #include "../common/inbound.h"
53 #include "../common/plugin.h"
54 #include "../common/modes.h"
55 #include "../common/url.h"
64 #include "userlistgui.h"
67 #include "plugin-tray.h"
71 #include <gtk/gtktextview.h>
72 #include <gtkspell/gtkspell.h>
76 #include "sexy-spell-entry.h"
79 #define GUI_SPACING (3)
80 #define GUI_BORDER (0)
81 #define SCROLLBAR_SPACING (2)
90 POS_TOP
= 5, /* for tabs only */
95 /* two different types of tabs */
96 #define TAG_IRC 0 /* server, channel, dialog */
97 #define TAG_UTIL 1 /* dcc, notify, chanlist */
99 static void mg_create_entry (session
*sess
, GtkWidget
*box
);
100 static void mg_link_irctab (session
*sess
, int focus
);
102 static session_gui static_mg_gui
;
103 static session_gui
*mg_gui
= NULL
; /* the shared irc tab */
104 static int ignore_chanmode
= FALSE
;
105 static const char chan_flags
[] = { 't', 'n', 's', 'i', 'p', 'm', 'l', 'k' };
107 static chan
*active_tab
= NULL
; /* active tab */
108 GtkWidget
*parent_window
= NULL
; /* the master window */
110 GtkStyle
*input_style
;
112 static PangoAttrList
*away_list
;
113 static PangoAttrList
*newdata_list
;
114 static PangoAttrList
*nickseen_list
;
115 static PangoAttrList
*newmsg_list
;
116 static PangoAttrList
*plain_list
= NULL
;
121 /* use these when it's a GtkTextView instead of GtkEntry */
124 SPELL_ENTRY_GET_TEXT (GtkWidget
*entry
)
126 static char *last
= NULL
; /* warning: don't overlap 2 GET_TEXT calls! */
127 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
128 GtkTextIter start_iter
, end_iter
;
130 gtk_text_buffer_get_iter_at_offset (buf
, &start_iter
, 0);
131 gtk_text_buffer_get_end_iter (buf
, &end_iter
);
133 last
= gtk_text_buffer_get_text (buf
, &start_iter
, &end_iter
, FALSE
);
138 SPELL_ENTRY_SET_POS (GtkWidget
*entry
, int pos
)
141 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
143 gtk_text_buffer_get_iter_at_offset (buf
, &iter
, pos
);
144 gtk_text_buffer_place_cursor (buf
, &iter
);
148 SPELL_ENTRY_GET_POS (GtkWidget
*entry
)
151 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
153 gtk_text_buffer_get_iter_at_mark (buf
, &cursor
, gtk_text_buffer_get_insert (buf
));
154 return gtk_text_iter_get_offset (&cursor
);
158 SPELL_ENTRY_INSERT (GtkWidget
*entry
, const char *text
, int len
, int *pos
)
161 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
163 /* len is bytes. pos is chars. */
164 gtk_text_buffer_get_iter_at_offset (buf
, &iter
, *pos
);
165 gtk_text_buffer_insert (buf
, &iter
, text
, len
);
166 *pos
+= g_utf8_strlen (text
, len
);
171 static PangoAttrList
*
172 mg_attr_list_create (GdkColor
*col
, int size
)
174 PangoAttribute
*attr
;
177 list
= pango_attr_list_new ();
181 attr
= pango_attr_foreground_new (col
->red
, col
->green
, col
->blue
);
182 attr
->start_index
= 0;
183 attr
->end_index
= 0xffff;
184 pango_attr_list_insert (list
, attr
);
189 attr
= pango_attr_scale_new (size
== 1 ? PANGO_SCALE_SMALL
: PANGO_SCALE_X_SMALL
);
190 attr
->start_index
= 0;
191 attr
->end_index
= 0xffff;
192 pango_attr_list_insert (list
, attr
);
199 mg_create_tab_colors (void)
203 pango_attr_list_unref (plain_list
);
204 pango_attr_list_unref (newmsg_list
);
205 pango_attr_list_unref (newdata_list
);
206 pango_attr_list_unref (nickseen_list
);
207 pango_attr_list_unref (away_list
);
210 plain_list
= mg_attr_list_create (NULL
, prefs
.tab_small
);
211 newdata_list
= mg_attr_list_create (&colors
[COL_NEW_DATA
], prefs
.tab_small
);
212 nickseen_list
= mg_attr_list_create (&colors
[COL_HILIGHT
], prefs
.tab_small
);
213 newmsg_list
= mg_attr_list_create (&colors
[COL_NEW_MSG
], prefs
.tab_small
);
214 away_list
= mg_attr_list_create (&colors
[COL_AWAY
], FALSE
);
218 #include <gdk/gdkx.h>
221 set_window_urgency (GtkWidget
*win
, gboolean set
)
225 hints
= XGetWMHints(GDK_WINDOW_XDISPLAY(win
->window
), GDK_WINDOW_XWINDOW(win
->window
));
227 hints
->flags
|= XUrgencyHint
;
229 hints
->flags
&= ~XUrgencyHint
;
230 XSetWMHints(GDK_WINDOW_XDISPLAY(win
->window
),
231 GDK_WINDOW_XWINDOW(win
->window
), hints
);
236 flash_window (GtkWidget
*win
)
238 set_window_urgency (win
, TRUE
);
242 unflash_window (GtkWidget
*win
)
244 set_window_urgency (win
, FALSE
);
248 /* flash the taskbar button */
251 fe_flash_window (session
*sess
)
253 #if defined(USE_XLIB)
254 if (fe_gui_info (sess
, 0) != 1) /* only do it if not focused */
255 flash_window (sess
->gui
->window
);
259 /* set a tab plain, red, light-red, or blue */
262 fe_set_tab_color (struct session
*sess
, int col
)
264 struct session
*server_sess
= sess
->server
->server_session
;
265 if (sess
->gui
->is_tab
&& (col
== 0 || sess
!= current_tab
))
269 case 0: /* no particular color (theme default) */
270 sess
->new_data
= FALSE
;
271 sess
->msg_said
= FALSE
;
272 sess
->nick_said
= FALSE
;
273 chan_set_color (sess
->res
->tab
, plain_list
);
275 case 1: /* new data has been displayed (dark red) */
276 sess
->new_data
= TRUE
;
277 sess
->msg_said
= FALSE
;
278 sess
->nick_said
= FALSE
;
279 chan_set_color (sess
->res
->tab
, newdata_list
);
281 if (chan_is_collapsed (sess
->res
->tab
)
282 && !(server_sess
->msg_said
|| server_sess
->nick_said
))
284 server_sess
->new_data
= TRUE
;
285 server_sess
->msg_said
= FALSE
;
286 server_sess
->nick_said
= FALSE
;
287 chan_set_color (chan_get_parent (sess
->res
->tab
), newdata_list
);
291 case 2: /* new message arrived in channel (light red) */
292 sess
->new_data
= FALSE
;
293 sess
->msg_said
= TRUE
;
294 sess
->nick_said
= FALSE
;
295 chan_set_color (sess
->res
->tab
, newmsg_list
);
297 if (chan_is_collapsed (sess
->res
->tab
) && !server_sess
->nick_said
)
299 server_sess
->new_data
= FALSE
;
300 server_sess
->msg_said
= TRUE
;
301 server_sess
->nick_said
= FALSE
;
302 chan_set_color (chan_get_parent (sess
->res
->tab
), newmsg_list
);
306 case 3: /* your nick has been seen (blue) */
307 sess
->new_data
= FALSE
;
308 sess
->msg_said
= FALSE
;
309 sess
->nick_said
= TRUE
;
310 chan_set_color (sess
->res
->tab
, nickseen_list
);
312 if (chan_is_collapsed (sess
->res
->tab
))
314 server_sess
->new_data
= FALSE
;
315 server_sess
->msg_said
= FALSE
;
316 server_sess
->nick_said
= TRUE
;
317 chan_set_color (chan_get_parent (sess
->res
->tab
), nickseen_list
);
326 mg_set_myself_away (session_gui
*gui
, gboolean away
)
328 gtk_label_set_attributes (GTK_LABEL (GTK_BIN (gui
->nick_label
)->child
),
329 away
? away_list
: NULL
);
332 /* change the little icon to the left of your nickname */
335 mg_set_access_icon (session_gui
*gui
, GdkPixbuf
*pix
, gboolean away
)
339 if (pix
== gtk_image_get_pixbuf (GTK_IMAGE (gui
->op_xpm
))) /* no change? */
341 mg_set_myself_away (gui
, away
);
345 gtk_widget_destroy (gui
->op_xpm
);
351 gui
->op_xpm
= gtk_image_new_from_pixbuf (pix
);
352 gtk_box_pack_start (GTK_BOX (gui
->nick_box
), gui
->op_xpm
, 0, 0, 0);
353 gtk_widget_show (gui
->op_xpm
);
356 mg_set_myself_away (gui
, away
);
360 mg_inputbox_focus (GtkWidget
*widget
, GdkEventFocus
*event
, session_gui
*gui
)
372 if (sess
->gui
== gui
)
375 if (!sess
->server
->server_session
)
376 sess
->server
->server_session
= sess
;
386 mg_inputbox_cb (GtkWidget
*igad
, session_gui
*gui
)
389 static int ignore
= FALSE
;
391 session
*sess
= NULL
;
396 cmd
= SPELL_ENTRY_GET_TEXT (igad
);
402 /* avoid recursive loop */
404 SPELL_ENTRY_SET_TEXT (igad
, "");
407 /* where did this event come from? */
417 if (sess
->gui
== gui
)
426 handle_multiline (sess
, cmd
, TRUE
, FALSE
);
432 has_key (char *modes
)
436 /* this is a crude check, but "-k" can't exist, so it works. */
449 fe_set_title (session
*sess
)
454 if (sess
->gui
->is_tab
&& sess
!= current_tab
)
459 if (sess
->server
->connected
== FALSE
&& sess
->type
!= SESS_DIALOG
)
465 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s %s @ %s",
466 _("Dialog with"), sess
->channel
, server_get_network (sess
->server
, TRUE
));
469 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s @ %s",
470 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
));
473 /* don't display keys in the titlebar */
474 if ((!(prefs
.gui_tweaks
& 16)) && has_key (sess
->current_modes
))
475 snprintf (tbuf
, sizeof (tbuf
),
476 DISPLAY_NAME
": %s @ %s / %s",
477 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
),
480 snprintf (tbuf
, sizeof (tbuf
),
481 DISPLAY_NAME
": %s @ %s / %s (%s)",
482 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
),
483 sess
->channel
, sess
->current_modes
? sess
->current_modes
: "");
484 if (prefs
.gui_tweaks
& 1)
485 snprintf (tbuf
+ strlen (tbuf
), 9, " (%d)", sess
->total
);
489 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s @ %s (notices)",
490 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
));
494 gtk_window_set_title (GTK_WINDOW (sess
->gui
->window
), DISPLAY_NAME
);
498 gtk_window_set_title (GTK_WINDOW (sess
->gui
->window
), tbuf
);
502 mg_windowstate_cb (GtkWindow
*wid
, GdkEventWindowState
*event
, gpointer userdata
)
504 prefs
.gui_win_state
= 0;
505 if (event
->new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
)
506 prefs
.gui_win_state
= 1;
508 if ((event
->changed_mask
& GDK_WINDOW_STATE_ICONIFIED
) &&
509 (event
->new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) &&
510 (prefs
.gui_tray_flags
& 4))
512 tray_toggle_visibility (TRUE
);
513 gtk_window_deiconify (wid
);
520 mg_configure_cb (GtkWidget
*wid
, GdkEventConfigure
*event
, session
*sess
)
522 if (sess
== NULL
) /* for the main_window */
526 if (prefs
.mainwindow_save
)
529 gtk_window_get_position (GTK_WINDOW (wid
), &prefs
.mainwindow_left
,
530 &prefs
.mainwindow_top
);
531 gtk_window_get_size (GTK_WINDOW (wid
), &prefs
.mainwindow_width
,
532 &prefs
.mainwindow_height
);
539 if (sess
->type
== SESS_DIALOG
&& prefs
.mainwindow_save
)
541 gtk_window_get_position (GTK_WINDOW (wid
), &prefs
.dialog_left
,
543 gtk_window_get_size (GTK_WINDOW (wid
), &prefs
.dialog_width
,
544 &prefs
.dialog_height
);
547 if (((GtkXText
*) sess
->gui
->xtext
)->transparent
)
548 gtk_widget_queue_draw (sess
->gui
->xtext
);
554 /* move to a non-irc tab */
557 mg_show_generic_tab (GtkWidget
*box
)
562 #if defined(GTK_WIDGET_HAS_FOCUS)
563 if (current_sess
&& GTK_WIDGET_HAS_FOCUS (current_sess
->gui
->input_box
))
565 if (current_sess
&& gtk_widget_has_focus (current_sess
->gui
->input_box
))
567 f
= current_sess
->gui
->input_box
;
569 num
= gtk_notebook_page_num (GTK_NOTEBOOK (mg_gui
->note_book
), box
);
570 gtk_notebook_set_current_page (GTK_NOTEBOOK (mg_gui
->note_book
), num
);
571 gtk_tree_view_set_model (GTK_TREE_VIEW (mg_gui
->user_tree
), NULL
);
572 gtk_window_set_title (GTK_WINDOW (mg_gui
->window
),
573 g_object_get_data (G_OBJECT (box
), "title"));
574 gtk_widget_set_sensitive (mg_gui
->menu
, FALSE
);
577 gtk_widget_grab_focus (f
);
580 /* a channel has been focused */
583 mg_focus (session
*sess
)
585 if (sess
->gui
->is_tab
)
589 /* dirty trick to avoid auto-selection */
590 SPELL_ENTRY_SET_EDITABLE (sess
->gui
->input_box
, FALSE
);
591 gtk_widget_grab_focus (sess
->gui
->input_box
);
592 SPELL_ENTRY_SET_EDITABLE (sess
->gui
->input_box
, TRUE
);
594 sess
->server
->front_session
= sess
;
596 if (sess
->server
->server_session
!= NULL
)
598 if (sess
->server
->server_session
->type
!= SESS_SERVER
)
599 sess
->server
->server_session
= sess
;
602 sess
->server
->server_session
= sess
;
605 if (sess
->new_data
|| sess
->nick_said
|| sess
->msg_said
)
607 sess
->nick_said
= FALSE
;
608 sess
->msg_said
= FALSE
;
609 sess
->new_data
= FALSE
;
610 /* when called via mg_changui_new, is_tab might be true, but
611 sess->res->tab is still NULL. */
613 fe_set_tab_color (sess
, 0);
618 mg_progressbar_update (GtkWidget
*bar
)
621 static float pos
= 0;
629 gtk_progress_bar_set_orientation ((GtkProgressBar
*) bar
,
630 GTK_PROGRESS_RIGHT_TO_LEFT
);
634 gtk_progress_bar_set_orientation ((GtkProgressBar
*) bar
,
635 GTK_PROGRESS_LEFT_TO_RIGHT
);
639 gtk_progress_bar_set_fraction ((GtkProgressBar
*) bar
, pos
);
644 mg_progressbar_create (session_gui
*gui
)
646 gui
->bar
= gtk_progress_bar_new ();
647 gtk_box_pack_start (GTK_BOX (gui
->nick_box
), gui
->bar
, 0, 0, 0);
648 gtk_widget_show (gui
->bar
);
649 gui
->bartag
= fe_timeout_add (50, mg_progressbar_update
, gui
->bar
);
653 mg_progressbar_destroy (session_gui
*gui
)
655 fe_timeout_remove (gui
->bartag
);
656 gtk_widget_destroy (gui
->bar
);
661 /* switching tabs away from this one, so remember some info about it! */
664 mg_unpopulate (session
*sess
)
673 res
->input_text
= strdup (SPELL_ENTRY_GET_TEXT (gui
->input_box
));
674 res
->topic_text
= strdup (GTK_ENTRY (gui
->topic_entry
)->text
);
675 res
->limit_text
= strdup (GTK_ENTRY (gui
->limit_entry
)->text
);
676 res
->key_text
= strdup (GTK_ENTRY (gui
->key_entry
)->text
);
678 res
->lag_text
= strdup (gtk_label_get_text (GTK_LABEL (gui
->laginfo
)));
679 if (gui
->throttleinfo
)
680 res
->queue_text
= strdup (gtk_label_get_text (GTK_LABEL (gui
->throttleinfo
)));
682 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
683 res
->flag_wid_state
[i
] = GTK_TOGGLE_BUTTON (gui
->flag_wid
[i
])->active
;
685 res
->old_ul_value
= userlist_get_value (gui
->user_tree
);
687 res
->lag_value
= gtk_progress_bar_get_fraction (
688 GTK_PROGRESS_BAR (gui
->lagometer
));
689 if (gui
->throttlemeter
)
690 res
->queue_value
= gtk_progress_bar_get_fraction (
691 GTK_PROGRESS_BAR (gui
->throttlemeter
));
695 res
->c_graph
= TRUE
; /* still have a graph, just not visible now */
696 mg_progressbar_destroy (gui
);
701 mg_restore_label (GtkWidget
*label
, char **text
)
708 gtk_label_set_text (GTK_LABEL (label
), *text
);
713 gtk_label_set_text (GTK_LABEL (label
), "");
718 mg_restore_entry (GtkWidget
*entry
, char **text
)
722 gtk_entry_set_text (GTK_ENTRY (entry
), *text
);
727 gtk_entry_set_text (GTK_ENTRY (entry
), "");
729 gtk_editable_set_position (GTK_EDITABLE (entry
), -1);
733 mg_restore_speller (GtkWidget
*entry
, char **text
)
737 SPELL_ENTRY_SET_TEXT (entry
, *text
);
742 SPELL_ENTRY_SET_TEXT (entry
, "");
744 SPELL_ENTRY_SET_POS (entry
, -1);
748 mg_set_topic_tip (session
*sess
)
757 text
= g_strdup_printf (_("Topic for %s is: %s"), sess
->channel
,
759 add_tip (sess
->gui
->topic_entry
, text
);
762 add_tip (sess
->gui
->topic_entry
, _("No topic is set"));
765 if (GTK_ENTRY (sess
->gui
->topic_entry
)->text
&&
766 GTK_ENTRY (sess
->gui
->topic_entry
)->text
[0])
767 add_tip (sess
->gui
->topic_entry
, GTK_ENTRY (sess
->gui
->topic_entry
)->text
);
769 add_tip (sess
->gui
->topic_entry
, NULL
);
774 mg_hide_empty_pane (GtkPaned
*pane
)
776 #if defined(GTK_WIDGET_VISIBLE)
777 if ((pane
->child1
== NULL
|| !GTK_WIDGET_VISIBLE (pane
->child1
)) &&
778 (pane
->child2
== NULL
|| !GTK_WIDGET_VISIBLE (pane
->child2
)))
780 if ((pane
->child1
== NULL
|| !gtk_widget_get_visible (pane
->child1
)) &&
781 (pane
->child2
== NULL
|| !gtk_widget_get_visible (pane
->child2
)))
784 gtk_widget_hide (GTK_WIDGET (pane
));
788 gtk_widget_show (GTK_WIDGET (pane
));
792 mg_hide_empty_boxes (session_gui
*gui
)
794 /* hide empty vpanes - so the handle is not shown */
795 mg_hide_empty_pane ((GtkPaned
*)gui
->vpane_right
);
796 mg_hide_empty_pane ((GtkPaned
*)gui
->vpane_left
);
800 mg_userlist_showhide (session
*sess
, int show
)
802 session_gui
*gui
= sess
->gui
;
807 gtk_widget_show (gui
->user_box
);
810 gtk_widget_style_get (GTK_WIDGET (gui
->hpane_right
), "handle-size", &handle_size
, NULL
);
811 gtk_paned_set_position (GTK_PANED (gui
->hpane_right
), GTK_WIDGET (gui
->hpane_right
)->allocation
.width
- (prefs
.gui_pane_right_size
+ handle_size
));
815 gtk_widget_hide (gui
->user_box
);
819 mg_hide_empty_boxes (gui
);
823 mg_is_userlist_and_tree_combined (void)
825 if (prefs
.tab_pos
== POS_TOPLEFT
&& prefs
.gui_ulist_pos
== POS_BOTTOMLEFT
)
827 if (prefs
.tab_pos
== POS_BOTTOMLEFT
&& prefs
.gui_ulist_pos
== POS_TOPLEFT
)
830 if (prefs
.tab_pos
== POS_TOPRIGHT
&& prefs
.gui_ulist_pos
== POS_BOTTOMRIGHT
)
832 if (prefs
.tab_pos
== POS_BOTTOMRIGHT
&& prefs
.gui_ulist_pos
== POS_TOPRIGHT
)
838 /* decide if the userlist should be shown or hidden for this tab */
841 mg_decide_userlist (session
*sess
, gboolean switch_to_current
)
843 /* when called from menu.c we need this */
844 if (sess
->gui
== mg_gui
&& switch_to_current
)
847 if (prefs
.hideuserlist
)
849 mg_userlist_showhide (sess
, FALSE
);
859 if (mg_is_userlist_and_tree_combined ())
860 mg_userlist_showhide (sess
, TRUE
); /* show */
862 mg_userlist_showhide (sess
, FALSE
); /* hide */
865 mg_userlist_showhide (sess
, TRUE
); /* show */
870 mg_userlist_toggle_cb (GtkWidget
*button
, gpointer userdata
)
872 prefs
.hideuserlist
= !prefs
.hideuserlist
;
873 mg_decide_userlist (current_sess
, FALSE
);
874 gtk_widget_grab_focus (current_sess
->gui
->input_box
);
877 static int ul_tag
= 0;
880 mg_populate_userlist (session
*sess
)
887 if (is_session (sess
))
890 if (sess
->type
== SESS_DIALOG
)
891 mg_set_access_icon (sess
->gui
, NULL
, sess
->server
->is_away
);
893 mg_set_access_icon (sess
->gui
, get_user_icon (sess
->server
, sess
->me
), sess
->server
->is_away
);
894 userlist_show (sess
);
895 userlist_set_value (sess
->gui
->user_tree
, sess
->res
->old_ul_value
);
902 /* fill the irc tab with a new channel */
905 mg_populate (session
*sess
)
907 session_gui
*gui
= sess
->gui
;
908 restore_gui
*res
= sess
->res
;
909 int i
, render
= TRUE
;
910 guint16 vis
= gui
->ul_hidden
;
915 /* show the dialog buttons */
916 gtk_widget_show (gui
->dialogbutton_box
);
917 /* hide the chan-mode buttons */
918 gtk_widget_hide (gui
->topicbutton_box
);
919 /* hide the userlist */
920 mg_decide_userlist (sess
, FALSE
);
921 /* shouldn't edit the topic */
922 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), FALSE
);
925 if (prefs
.chanmodebuttons
)
926 gtk_widget_show (gui
->topicbutton_box
);
927 /* hide the dialog buttons */
928 gtk_widget_hide (gui
->dialogbutton_box
);
929 /* hide the userlist */
930 mg_decide_userlist (sess
, FALSE
);
931 /* shouldn't edit the topic */
932 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), FALSE
);
935 /* hide the dialog buttons */
936 gtk_widget_hide (gui
->dialogbutton_box
);
937 if (prefs
.chanmodebuttons
)
938 gtk_widget_show (gui
->topicbutton_box
);
939 /* show the userlist */
940 mg_decide_userlist (sess
, FALSE
);
941 /* let the topic be editted */
942 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), TRUE
);
945 /* move to THE irc tab */
947 gtk_notebook_set_current_page (GTK_NOTEBOOK (gui
->note_book
), 0);
949 /* xtext size change? Then don't render, wait for the expose caused
950 by showing/hidding the userlist */
951 if (vis
!= gui
->ul_hidden
&& gui
->user_box
->allocation
.width
> 1)
954 gtk_xtext_buffer_show (GTK_XTEXT (gui
->xtext
), res
->buffer
, render
);
957 gtk_widget_set_sensitive (gui
->menu
, TRUE
);
959 /* restore all the GtkEntry's */
960 mg_restore_entry (gui
->topic_entry
, &res
->topic_text
);
961 mg_restore_speller (gui
->input_box
, &res
->input_text
);
962 mg_restore_entry (gui
->key_entry
, &res
->key_text
);
963 mg_restore_entry (gui
->limit_entry
, &res
->limit_text
);
964 mg_restore_label (gui
->laginfo
, &res
->lag_text
);
965 mg_restore_label (gui
->throttleinfo
, &res
->queue_text
);
970 /* this one flickers, so only change if necessary */
971 if (strcmp (sess
->server
->nick
, gtk_button_get_label (GTK_BUTTON (gui
->nick_label
))) != 0)
972 gtk_button_set_label (GTK_BUTTON (gui
->nick_label
), sess
->server
->nick
);
974 /* this is slow, so make it a timeout event */
977 mg_populate_userlist (sess
);
981 ul_tag
= g_idle_add ((GSourceFunc
)mg_populate_userlist
, NULL
);
984 fe_userlist_numbers (sess
);
986 /* restore all the channel mode buttons */
987 ignore_chanmode
= TRUE
;
988 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
989 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gui
->flag_wid
[i
]),
990 res
->flag_wid_state
[i
]);
991 ignore_chanmode
= FALSE
;
995 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui
->lagometer
),
998 add_tip (sess
->gui
->lagometer
->parent
, res
->lag_tip
);
1000 if (gui
->throttlemeter
)
1002 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui
->throttlemeter
),
1005 add_tip (sess
->gui
->throttlemeter
->parent
, res
->queue_tip
);
1008 /* did this tab have a connecting graph? restore it.. */
1011 res
->c_graph
= FALSE
;
1012 mg_progressbar_create (gui
);
1016 GTK_CHECK_MENU_ITEM (gui
->menu_item
[MENU_ID_AWAY
])->active
= sess
->server
->is_away
;
1017 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_AWAY
], sess
->server
->connected
);
1018 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_JOIN
], sess
->server
->end_of_motd
);
1019 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_DISCONNECT
],
1020 sess
->server
->connected
|| sess
->server
->recondelay_tag
);
1022 mg_set_topic_tip (sess
);
1024 plugin_emit_dummy_print (sess
, "Focus Tab");
1028 mg_bring_tofront_sess (session
*sess
) /* IRC tab or window */
1030 if (sess
->gui
->is_tab
)
1031 chan_focus (sess
->res
->tab
);
1033 gtk_window_present (GTK_WINDOW (sess
->gui
->window
));
1037 mg_bring_tofront (GtkWidget
*vbox
) /* non-IRC tab or window */
1041 ch
= g_object_get_data (G_OBJECT (vbox
), "ch");
1045 gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (vbox
)));
1049 mg_switch_page (int relative
, int num
)
1052 chanview_move_focus (mg_gui
->chanview
, relative
, num
);
1055 /* a toplevel IRC window was destroyed */
1058 mg_topdestroy_cb (GtkWidget
*win
, session
*sess
)
1060 /* printf("enter mg_topdestroy. sess %p was destroyed\n", sess);*/
1062 /* kill the text buffer */
1063 gtk_xtext_buffer_free (sess
->res
->buffer
);
1064 /* kill the user list */
1065 g_object_unref (G_OBJECT (sess
->res
->user_model
));
1067 session_free (sess
); /* tell xchat.c about it */
1070 /* cleanup an IRC tab */
1073 mg_ircdestroy (session
*sess
)
1077 /* kill the text buffer */
1078 gtk_xtext_buffer_free (sess
->res
->buffer
);
1079 /* kill the user list */
1080 g_object_unref (G_OBJECT (sess
->res
->user_model
));
1082 session_free (sess
); /* tell xchat.c about it */
1086 /* puts("-> mg_gui is already NULL");*/
1094 if (sess
->gui
->is_tab
)
1096 /* puts("-> some tabs still remain");*/
1102 /* puts("-> no tabs left, killing main tabwindow");*/
1103 gtk_widget_destroy (mg_gui
->window
);
1106 parent_window
= NULL
;
1110 mg_tab_close_cb (GtkWidget
*dialog
, gint arg1
, session
*sess
)
1112 GSList
*list
, *next
;
1114 gtk_widget_destroy (dialog
);
1115 if (arg1
== GTK_RESPONSE_OK
&& is_session (sess
))
1117 /* force it NOT to send individual PARTs */
1118 sess
->server
->sent_quit
= TRUE
;
1120 for (list
= sess_list
; list
;)
1123 if (((session
*)list
->data
)->server
== sess
->server
&&
1124 ((session
*)list
->data
) != sess
)
1125 fe_close_window ((session
*)list
->data
);
1129 /* just send one QUIT - better for BNCs */
1130 sess
->server
->sent_quit
= FALSE
;
1131 fe_close_window (sess
);
1136 mg_tab_close (session
*sess
)
1142 if (chan_remove (sess
->res
->tab
, FALSE
))
1143 mg_ircdestroy (sess
);
1146 for (i
= 0, list
= sess_list
; list
; list
= list
->next
)
1147 if (((session
*)list
->data
)->server
== sess
->server
)
1149 dialog
= gtk_message_dialog_new (GTK_WINDOW (parent_window
), 0,
1150 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK_CANCEL
,
1151 _("This server still has %d channels or dialogs associated with it. "
1152 "Close them all?"), i
);
1153 g_signal_connect (G_OBJECT (dialog
), "response",
1154 G_CALLBACK (mg_tab_close_cb
), sess
);
1155 if (prefs
.tab_layout
)
1157 gtk_window_set_position (GTK_WINDOW (dialog
), GTK_WIN_POS_MOUSE
);
1161 gtk_window_set_position (GTK_WINDOW (dialog
), GTK_WIN_POS_CENTER_ON_PARENT
);
1163 gtk_widget_show (dialog
);
1168 mg_menu_destroy (GtkWidget
*menu
, gpointer userdata
)
1170 gtk_widget_destroy (menu
);
1171 g_object_unref (menu
);
1175 mg_create_icon_item (char *label
, char *stock
, GtkWidget
*menu
,
1176 void *callback
, void *userdata
)
1180 item
= create_icon_menu (label
, stock
, TRUE
);
1181 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1182 g_signal_connect (G_OBJECT (item
), "activate", G_CALLBACK (callback
),
1184 gtk_widget_show (item
);
1188 mg_count_networks (void)
1193 for (list
= serv_list
; list
; list
= list
->next
)
1195 if (((server
*)list
->data
)->connected
)
1202 mg_count_dccs (void)
1212 if ((dcc
->type
== TYPE_SEND
|| dcc
->type
== TYPE_RECV
) &&
1213 dcc
->dccstat
== STAT_ACTIVE
)
1222 mg_open_quit_dialog (gboolean minimize_button
)
1224 static GtkWidget
*dialog
= NULL
;
1225 GtkWidget
*dialog_vbox1
;
1228 GtkWidget
*checkbutton1
;
1230 GtkWidget
*dialog_action_area1
;
1232 char *text
, *connecttext
;
1238 gtk_window_present (GTK_WINDOW (dialog
));
1242 dccs
= mg_count_dccs ();
1243 cons
= mg_count_networks ();
1244 if (dccs
+ cons
== 0 || !prefs
.gui_quit_dialog
)
1250 dialog
= gtk_dialog_new ();
1251 gtk_container_set_border_width (GTK_CONTAINER (dialog
), 6);
1252 gtk_window_set_title (GTK_WINDOW (dialog
), _("Quit XChat?"));
1253 gtk_window_set_transient_for (GTK_WINDOW (dialog
), GTK_WINDOW (parent_window
));
1254 gtk_window_set_resizable (GTK_WINDOW (dialog
), FALSE
);
1255 gtk_dialog_set_has_separator (GTK_DIALOG (dialog
), FALSE
);
1257 dialog_vbox1
= GTK_DIALOG (dialog
)->vbox
;
1258 gtk_widget_show (dialog_vbox1
);
1260 table1
= gtk_table_new (2, 2, FALSE
);
1261 gtk_widget_show (table1
);
1262 gtk_box_pack_start (GTK_BOX (dialog_vbox1
), table1
, TRUE
, TRUE
, 0);
1263 gtk_container_set_border_width (GTK_CONTAINER (table1
), 6);
1264 gtk_table_set_row_spacings (GTK_TABLE (table1
), 12);
1265 gtk_table_set_col_spacings (GTK_TABLE (table1
), 12);
1267 image
= gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_DIALOG
);
1268 gtk_widget_show (image
);
1269 gtk_table_attach (GTK_TABLE (table1
), image
, 0, 1, 0, 1,
1270 (GtkAttachOptions
) (GTK_FILL
),
1271 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1273 checkbutton1
= gtk_check_button_new_with_mnemonic (_("Don't ask next time."));
1274 gtk_widget_show (checkbutton1
);
1275 gtk_table_attach (GTK_TABLE (table1
), checkbutton1
, 0, 2, 1, 2,
1276 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1277 (GtkAttachOptions
) (0), 0, 4);
1279 connecttext
= g_strdup_printf (_("You are connected to %i IRC networks."), cons
);
1280 text
= g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n%s",
1281 _("Are you sure you want to quit?"),
1282 cons
? connecttext
: "",
1283 dccs
? _("Some file transfers are still active.") : "");
1284 g_free (connecttext
);
1285 label
= gtk_label_new (text
);
1287 gtk_widget_show (label
);
1288 gtk_table_attach (GTK_TABLE (table1
), label
, 1, 2, 0, 1,
1289 (GtkAttachOptions
) (GTK_EXPAND
| GTK_SHRINK
| GTK_FILL
),
1290 (GtkAttachOptions
) (GTK_EXPAND
| GTK_SHRINK
), 0, 0);
1291 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
1292 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
1294 dialog_action_area1
= GTK_DIALOG (dialog
)->action_area
;
1295 gtk_widget_show (dialog_action_area1
);
1296 gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1
),
1299 if (minimize_button
)
1301 button
= gtk_button_new_with_mnemonic (_("_Minimize to Tray"));
1302 gtk_widget_show (button
);
1303 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
, 1);
1306 button
= gtk_button_new_from_stock ("gtk-cancel");
1307 gtk_widget_show (button
);
1308 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
,
1309 GTK_RESPONSE_CANCEL
);
1310 gtk_widget_grab_focus (button
);
1312 button
= gtk_button_new_from_stock ("gtk-quit");
1313 gtk_widget_show (button
);
1314 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
, 0);
1316 gtk_widget_show (dialog
);
1318 switch (gtk_dialog_run (GTK_DIALOG (dialog
)))
1321 if (GTK_TOGGLE_BUTTON (checkbutton1
)->active
)
1322 prefs
.gui_quit_dialog
= 0;
1325 case 1: /* minimize to tray */
1326 if (GTK_TOGGLE_BUTTON (checkbutton1
)->active
)
1328 prefs
.gui_tray_flags
|= 1;
1329 /*prefs.gui_quit_dialog = 0;*/
1331 /* force tray icon ON, if not already */
1332 if (!prefs
.gui_tray
)
1335 tray_apply_setup ();
1337 tray_toggle_visibility (TRUE
);
1341 gtk_widget_destroy (dialog
);
1346 mg_close_sess (session
*sess
)
1348 if (sess_list
->next
== NULL
)
1350 mg_open_quit_dialog (FALSE
);
1354 fe_close_window (sess
);
1358 mg_chan_remove (chan
*ch
)
1360 /* remove the tab from chanview */
1361 chan_remove (ch
, TRUE
);
1362 /* any tabs left? */
1363 if (chanview_get_size (mg_gui
->chanview
) < 1)
1365 /* if not, destroy the main tab window */
1366 gtk_widget_destroy (mg_gui
->window
);
1370 parent_window
= NULL
;
1376 /* destroy non-irc tab/window */
1379 mg_close_gen (chan
*ch
, GtkWidget
*box
)
1381 char *title
= g_object_get_data (G_OBJECT (box
), "title");
1386 ch
= g_object_get_data (G_OBJECT (box
), "ch");
1389 /* remove from notebook */
1390 gtk_widget_destroy (box
);
1391 /* remove the tab from chanview */
1392 mg_chan_remove (ch
);
1395 gtk_widget_destroy (gtk_widget_get_toplevel (box
));
1399 /* the "X" close button has been pressed (tab-view) */
1402 mg_xbutton_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer userdata
)
1404 if (tag
== TAG_IRC
) /* irc tab */
1405 mg_close_sess (userdata
);
1406 else /* non-irc utility tab */
1407 mg_close_gen (ch
, userdata
);
1411 mg_link_gentab (chan
*ch
, GtkWidget
*box
)
1418 num
= gtk_notebook_page_num (GTK_NOTEBOOK (mg_gui
->note_book
), box
);
1419 gtk_notebook_remove_page (GTK_NOTEBOOK (mg_gui
->note_book
), num
);
1420 mg_chan_remove (ch
);
1422 win
= gtkutil_window_new (g_object_get_data (G_OBJECT (box
), "title"), "",
1423 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (box
), "w")),
1424 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (box
), "h")),
1426 /* so it doesn't try to chan_remove (there's no tab anymore) */
1427 g_object_steal_data (G_OBJECT (box
), "ch");
1428 gtk_container_set_border_width (GTK_CONTAINER (box
), 0);
1429 gtk_container_add (GTK_CONTAINER (win
), box
);
1430 gtk_widget_show (win
);
1432 g_object_unref (box
);
1436 mg_detach_tab_cb (GtkWidget
*item
, chan
*ch
)
1438 if (chan_get_tag (ch
) == TAG_IRC
) /* IRC tab */
1440 /* userdata is session * */
1441 mg_link_irctab (chan_get_userdata (ch
), 1);
1445 /* userdata is GtkWidget * */
1446 mg_link_gentab (ch
, chan_get_userdata (ch
)); /* non-IRC tab */
1450 mg_destroy_tab_cb (GtkWidget
*item
, chan
*ch
)
1452 /* treat it just like the X button press */
1453 mg_xbutton_cb (mg_gui
->chanview
, ch
, chan_get_tag (ch
), chan_get_userdata (ch
));
1457 mg_color_insert (GtkWidget
*item
, gpointer userdata
)
1461 int num
= GPOINTER_TO_INT (userdata
);
1468 text
= "\002"; break;
1470 text
= "\037"; break;
1472 text
= "\035"; break;
1474 text
= "\017"; break;
1476 key_action_insert (current_sess
->gui
->input_box
, 0, text
, 0, 0);
1479 sprintf (buf
, "\003%02d", num
);
1480 key_action_insert (current_sess
->gui
->input_box
, 0, buf
, 0, 0);
1485 mg_markup_item (GtkWidget
*menu
, char *text
, int arg
)
1489 item
= gtk_menu_item_new_with_label ("");
1490 gtk_label_set_markup (GTK_LABEL (GTK_BIN (item
)->child
), text
);
1491 g_signal_connect (G_OBJECT (item
), "activate",
1492 G_CALLBACK (mg_color_insert
), GINT_TO_POINTER (arg
));
1493 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1494 gtk_widget_show (item
);
1498 mg_submenu (GtkWidget
*menu
, char *text
)
1500 GtkWidget
*submenu
, *item
;
1502 item
= gtk_menu_item_new_with_mnemonic (text
);
1503 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1504 gtk_widget_show (item
);
1506 submenu
= gtk_menu_new ();
1507 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item
), submenu
);
1508 gtk_widget_show (submenu
);
1514 mg_create_color_menu (GtkWidget
*menu
, session
*sess
)
1517 GtkWidget
*subsubmenu
;
1521 submenu
= mg_submenu (menu
, _("Insert Attribute or Color Code"));
1523 mg_markup_item (submenu
, _("<b>Bold</b>"), 100);
1524 mg_markup_item (submenu
, _("<u>Underline</u>"), 101);
1525 /*mg_markup_item (submenu, _("<i>Italic</i>"), 102);*/
1526 mg_markup_item (submenu
, _("Normal"), 103);
1528 subsubmenu
= mg_submenu (submenu
, _("Colors 0-7"));
1530 for (i
= 0; i
< 8; i
++)
1532 sprintf (buf
, "<tt><sup>%02d</sup> <span background=\"#%02x%02x%02x\">"
1534 i
, colors
[i
].red
>> 8, colors
[i
].green
>> 8, colors
[i
].blue
>> 8);
1535 mg_markup_item (subsubmenu
, buf
, i
);
1538 subsubmenu
= mg_submenu (submenu
, _("Colors 8-15"));
1540 for (i
= 8; i
< 16; i
++)
1542 sprintf (buf
, "<tt><sup>%02d</sup> <span background=\"#%02x%02x%02x\">"
1544 i
, colors
[i
].red
>> 8, colors
[i
].green
>> 8, colors
[i
].blue
>> 8);
1545 mg_markup_item (subsubmenu
, buf
, i
);
1550 mg_set_guint8 (GtkCheckMenuItem
*item
, guint8
*setting
)
1552 session
*sess
= current_sess
;
1553 guint8 logging
= sess
->text_logging
;
1559 /* has the logging setting changed? */
1560 if (logging
!= sess
->text_logging
)
1561 log_open_or_close (sess
);
1565 mg_perchan_menu_item (char *label
, GtkWidget
*menu
, guint8
*setting
, guint global
)
1567 guint8 initial_value
= *setting
;
1569 /* if it's using global value, use that as initial state */
1570 if (initial_value
== SET_DEFAULT
)
1571 initial_value
= global
;
1573 menu_toggle_item (label
, menu
, mg_set_guint8
, setting
, initial_value
);
1577 mg_create_perchannelmenu (session
*sess
, GtkWidget
*menu
)
1581 submenu
= menu_quick_sub (_("_Settings"), menu
, NULL
, XCMENU_MNEMONIC
, -1);
1583 mg_perchan_menu_item (_("_Log to Disk"), submenu
, &sess
->text_logging
, prefs
.logging
);
1584 mg_perchan_menu_item (_("_Reload Scrollback"), submenu
, &sess
->text_scrollback
, prefs
.text_replay
);
1585 if (sess
->type
== SESS_CHANNEL
)
1586 mg_perchan_menu_item (_("_Hide Join/Part Messages"), submenu
, &sess
->text_hidejoinpart
, prefs
.confmode
);
1590 mg_create_alertmenu (session
*sess
, GtkWidget
*menu
)
1594 submenu
= menu_quick_sub (_("_Extra Alerts"), menu
, NULL
, XCMENU_MNEMONIC
, -1);
1596 mg_perchan_menu_item (_("Beep on _Message"), submenu
, &sess
->alert_beep
, prefs
.input_beep_chans
);
1597 mg_perchan_menu_item (_("Blink Tray _Icon"), submenu
, &sess
->alert_tray
, prefs
.input_tray_chans
);
1598 mg_perchan_menu_item (_("Blink Task _Bar"), submenu
, &sess
->alert_taskbar
, prefs
.input_flash_chans
);
1602 mg_create_tabmenu (session
*sess
, GdkEventButton
*event
, chan
*ch
)
1604 GtkWidget
*menu
, *item
;
1607 menu
= gtk_menu_new ();
1611 char *name
= g_markup_escape_text (sess
->channel
[0] ? sess
->channel
: _("<none>"), -1);
1612 snprintf (buf
, sizeof (buf
), "<span foreground=\"#3344cc\"><b>%s</b></span>", name
);
1615 item
= gtk_menu_item_new_with_label ("");
1616 gtk_label_set_markup (GTK_LABEL (GTK_BIN (item
)->child
), buf
);
1617 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1618 gtk_widget_show (item
);
1621 menu_quick_item (0, 0, menu
, XCMENU_SHADED
, 0, 0);
1623 /* per-channel alerts */
1624 mg_create_alertmenu (sess
, menu
);
1626 /* per-channel settings */
1627 mg_create_perchannelmenu (sess
, menu
);
1630 menu_quick_item (0, 0, menu
, XCMENU_SHADED
, 0, 0);
1632 if (sess
->type
== SESS_CHANNEL
)
1633 menu_addfavoritemenu (sess
->server
, menu
, sess
->channel
);
1636 mg_create_icon_item (_("_Detach"), GTK_STOCK_REDO
, menu
,
1637 mg_detach_tab_cb
, ch
);
1638 mg_create_icon_item (_("_Close"), GTK_STOCK_CLOSE
, menu
,
1639 mg_destroy_tab_cb
, ch
);
1640 if (sess
&& tabmenu_list
)
1641 menu_create (menu
, tabmenu_list
, sess
->channel
, FALSE
);
1642 menu_add_plugin_items (menu
, "\x4$TAB", sess
->channel
);
1645 gtk_menu_set_screen (GTK_MENU (menu
), gdk_drawable_get_screen (event
->window
));
1646 g_object_ref (menu
);
1647 g_object_ref_sink (menu
);
1648 g_object_unref (menu
);
1649 g_signal_connect (G_OBJECT (menu
), "selection-done",
1650 G_CALLBACK (mg_menu_destroy
), NULL
);
1651 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
1655 mg_tab_contextmenu_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer ud
, GdkEventButton
*event
)
1657 /* shift-click to close a tab */
1658 if ((event
->state
& GDK_SHIFT_MASK
) && event
->type
== GDK_BUTTON_PRESS
)
1660 mg_xbutton_cb (cv
, ch
, tag
, ud
);
1664 if (event
->button
!= 3)
1668 mg_create_tabmenu (ud
, event
, ch
);
1670 mg_create_tabmenu (NULL
, event
, ch
);
1676 mg_dnd_drop_file (session
*sess
, char *target
, char *uri
)
1678 char *p
, *data
, *next
, *fname
;
1680 p
= data
= strdup (uri
);
1683 next
= strchr (p
, '\r');
1684 if (strncasecmp ("file:", p
, 5) == 0)
1688 fname
= g_filename_from_uri (p
, NULL
, NULL
);
1691 /* dcc_send() expects utf-8 */
1692 p
= xchat_filename_to_utf8 (fname
, -1, 0, 0, 0);
1695 dcc_send (sess
, target
, p
, prefs
.dcc_max_send_cps
, 0);
1712 mg_dialog_dnd_drop (GtkWidget
* widget
, GdkDragContext
* context
, gint x
,
1713 gint y
, GtkSelectionData
* selection_data
, guint info
,
1714 guint32 time
, gpointer ud
)
1716 if (current_sess
->type
== SESS_DIALOG
)
1717 /* sess->channel is really the nickname of dialogs */
1718 mg_dnd_drop_file (current_sess
, current_sess
->channel
, selection_data
->data
);
1721 /* add a tabbed channel */
1724 mg_add_chan (session
*sess
)
1727 char *name
= _("<none>");
1729 if (sess
->channel
[0])
1730 name
= sess
->channel
;
1744 sess
->res
->tab
= chanview_add (sess
->gui
->chanview
, name
, sess
->server
, sess
,
1745 sess
->type
== SESS_SERVER
? FALSE
: TRUE
,
1747 if (plain_list
== NULL
)
1748 mg_create_tab_colors ();
1750 chan_set_color (sess
->res
->tab
, plain_list
);
1752 if (sess
->res
->buffer
== NULL
)
1754 sess
->res
->buffer
= gtk_xtext_buffer_new (GTK_XTEXT (sess
->gui
->xtext
));
1755 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
1756 sess
->res
->user_model
= userlist_create_model ();
1761 mg_userlist_button (GtkWidget
* box
, char *label
, char *cmd
,
1762 int a
, int b
, int c
, int d
)
1764 GtkWidget
*wid
= gtk_button_new_with_label (label
);
1765 g_signal_connect (G_OBJECT (wid
), "clicked",
1766 G_CALLBACK (userlist_button_cb
), cmd
);
1767 gtk_table_attach_defaults (GTK_TABLE (box
), wid
, a
, b
, c
, d
);
1768 show_and_unfocus (wid
);
1772 mg_create_userlistbuttons (GtkWidget
*box
)
1775 GSList
*list
= button_list
;
1779 tab
= gtk_table_new (5, 2, FALSE
);
1780 gtk_box_pack_end (GTK_BOX (box
), tab
, FALSE
, FALSE
, 0);
1787 mg_userlist_button (tab
, pop
->name
, pop
->cmd
, a
, a
+ 1, b
, b
+ 1);
1802 mg_topic_cb (GtkWidget
*entry
, gpointer userdata
)
1804 session
*sess
= current_sess
;
1807 if (sess
->channel
[0] && sess
->server
->connected
&& sess
->type
== SESS_CHANNEL
)
1809 text
= GTK_ENTRY (entry
)->text
;
1812 sess
->server
->p_topic (sess
->server
, sess
->channel
, text
);
1814 gtk_entry_set_text (GTK_ENTRY (entry
), "");
1815 /* restore focus to the input widget, where the next input will most
1817 gtk_widget_grab_focus (sess
->gui
->input_box
);
1821 mg_tabwindow_kill_cb (GtkWidget
*win
, gpointer userdata
)
1823 GSList
*list
, *next
;
1826 /* puts("enter mg_tabwindow_kill_cb");*/
1827 xchat_is_quitting
= TRUE
;
1829 /* see if there's any non-tab windows left */
1835 if (!sess
->gui
->is_tab
)
1837 xchat_is_quitting
= FALSE
;
1838 /* puts("-> will not exit, some toplevel windows left");*/
1841 mg_ircdestroy (sess
);
1849 parent_window
= NULL
;
1853 mg_changui_destroy (session
*sess
)
1855 GtkWidget
*ret
= NULL
;
1857 if (sess
->gui
->is_tab
)
1859 /* avoid calling the "destroy" callback */
1860 g_signal_handlers_disconnect_by_func (G_OBJECT (sess
->gui
->window
),
1861 mg_tabwindow_kill_cb
, 0);
1862 /* remove the tab from the chanview */
1863 if (!mg_chan_remove (sess
->res
->tab
))
1864 /* if the window still exists, restore the signal handler */
1865 g_signal_connect (G_OBJECT (sess
->gui
->window
), "destroy",
1866 G_CALLBACK (mg_tabwindow_kill_cb
), 0);
1869 /* avoid calling the "destroy" callback */
1870 g_signal_handlers_disconnect_by_func (G_OBJECT (sess
->gui
->window
),
1871 mg_topdestroy_cb
, sess
);
1872 /*gtk_widget_destroy (sess->gui->window);*/
1873 /* don't destroy until the new one is created. Not sure why, but */
1874 /* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
1875 /* assertion `GDK_IS_COLORMAP (cmap)' failed */
1876 ret
= sess
->gui
->window
;
1884 mg_link_irctab (session
*sess
, int focus
)
1888 if (sess
->gui
->is_tab
)
1890 win
= mg_changui_destroy (sess
);
1891 mg_changui_new (sess
, sess
->res
, 0, focus
);
1893 xchat_is_quitting
= FALSE
;
1895 gtk_widget_destroy (win
);
1899 mg_unpopulate (sess
);
1900 win
= mg_changui_destroy (sess
);
1901 mg_changui_new (sess
, sess
->res
, 1, focus
);
1902 /* the buffer is now attached to a different widget */
1903 ((xtext_buffer
*)sess
->res
->buffer
)->xtext
= (GtkXText
*)sess
->gui
->xtext
;
1905 gtk_widget_destroy (win
);
1909 mg_detach (session
*sess
, int mode
)
1915 if (sess
->gui
->is_tab
)
1916 mg_link_irctab (sess
, 1);
1920 if (!sess
->gui
->is_tab
)
1921 mg_link_irctab (sess
, 1);
1925 mg_link_irctab (sess
, 1);
1930 check_is_number (char *t
)
1934 if (*t
< '0' || *t
> '9')
1942 mg_change_flag (GtkWidget
* wid
, session
*sess
, char flag
)
1944 server
*serv
= sess
->server
;
1949 if (serv
->connected
&& sess
->channel
[0])
1951 if (GTK_TOGGLE_BUTTON (wid
)->active
)
1955 serv
->p_mode (serv
, sess
->channel
, mode
);
1956 serv
->p_join_info (serv
, sess
->channel
);
1957 sess
->ignore_mode
= TRUE
;
1958 sess
->ignore_date
= TRUE
;
1963 flagl_hit (GtkWidget
* wid
, struct session
*sess
)
1966 const char *limit_str
;
1967 server
*serv
= sess
->server
;
1969 if (GTK_TOGGLE_BUTTON (wid
)->active
)
1971 if (serv
->connected
&& sess
->channel
[0])
1973 limit_str
= gtk_entry_get_text (GTK_ENTRY (sess
->gui
->limit_entry
));
1974 if (check_is_number ((char *)limit_str
) == FALSE
)
1976 fe_message (_("User limit must be a number!\n"), FE_MSG_ERROR
);
1977 gtk_entry_set_text (GTK_ENTRY (sess
->gui
->limit_entry
), "");
1978 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid
), FALSE
);
1981 snprintf (modes
, sizeof (modes
), "+l %d", atoi (limit_str
));
1982 serv
->p_mode (serv
, sess
->channel
, modes
);
1983 serv
->p_join_info (serv
, sess
->channel
);
1986 mg_change_flag (wid
, sess
, 'l');
1990 flagk_hit (GtkWidget
* wid
, struct session
*sess
)
1993 server
*serv
= sess
->server
;
1995 if (serv
->connected
&& sess
->channel
[0])
1997 snprintf (modes
, sizeof (modes
), "-k %s",
1998 gtk_entry_get_text (GTK_ENTRY (sess
->gui
->key_entry
)));
2000 if (GTK_TOGGLE_BUTTON (wid
)->active
)
2003 serv
->p_mode (serv
, sess
->channel
, modes
);
2008 mg_flagbutton_cb (GtkWidget
*but
, char *flag
)
2013 if (ignore_chanmode
)
2016 sess
= current_sess
;
2017 mode
= tolower ((unsigned char) flag
[0]);
2022 flagl_hit (but
, sess
);
2025 flagk_hit (but
, sess
);
2028 ignore_chanmode
= TRUE
;
2029 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess
->gui
->flag_b
), FALSE
);
2030 ignore_chanmode
= FALSE
;
2031 banlist_opengui (sess
);
2034 mg_change_flag (but
, sess
, mode
);
2039 mg_create_flagbutton (char *tip
, GtkWidget
*box
, char *face
)
2043 wid
= gtk_toggle_button_new_with_label (face
);
2044 gtk_widget_set_size_request (wid
, 18, 0);
2046 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2047 g_signal_connect (G_OBJECT (wid
), "toggled",
2048 G_CALLBACK (mg_flagbutton_cb
), face
);
2049 show_and_unfocus (wid
);
2055 mg_key_entry_cb (GtkWidget
* igad
, gpointer userdata
)
2058 session
*sess
= current_sess
;
2059 server
*serv
= sess
->server
;
2061 if (serv
->connected
&& sess
->channel
[0])
2063 snprintf (modes
, sizeof (modes
), "+k %s",
2064 gtk_entry_get_text (GTK_ENTRY (igad
)));
2065 serv
->p_mode (serv
, sess
->channel
, modes
);
2066 serv
->p_join_info (serv
, sess
->channel
);
2071 mg_limit_entry_cb (GtkWidget
* igad
, gpointer userdata
)
2074 session
*sess
= current_sess
;
2075 server
*serv
= sess
->server
;
2077 if (serv
->connected
&& sess
->channel
[0])
2079 if (check_is_number ((char *)gtk_entry_get_text (GTK_ENTRY (igad
))) == FALSE
)
2081 gtk_entry_set_text (GTK_ENTRY (igad
), "");
2082 fe_message (_("User limit must be a number!\n"), FE_MSG_ERROR
);
2083 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess
->gui
->flag_l
), FALSE
);
2086 snprintf (modes
, sizeof(modes
), "+l %d",
2087 atoi (gtk_entry_get_text (GTK_ENTRY (igad
))));
2088 serv
->p_mode (serv
, sess
->channel
, modes
);
2089 serv
->p_join_info (serv
, sess
->channel
);
2094 mg_apply_entry_style (GtkWidget
*entry
)
2096 gtk_widget_modify_base (entry
, GTK_STATE_NORMAL
, &colors
[COL_BG
]);
2097 gtk_widget_modify_text (entry
, GTK_STATE_NORMAL
, &colors
[COL_FG
]);
2098 gtk_widget_modify_font (entry
, input_style
->font_desc
);
2102 mg_create_chanmodebuttons (session_gui
*gui
, GtkWidget
*box
)
2104 gui
->flag_t
= mg_create_flagbutton (_("Topic Protection"), box
, "T");
2105 gui
->flag_n
= mg_create_flagbutton (_("No outside messages"), box
, "N");
2106 gui
->flag_s
= mg_create_flagbutton (_("Secret"), box
, "S");
2107 gui
->flag_i
= mg_create_flagbutton (_("Invite Only"), box
, "I");
2108 gui
->flag_p
= mg_create_flagbutton (_("Private"), box
, "P");
2109 gui
->flag_m
= mg_create_flagbutton (_("Moderated"), box
, "M");
2110 gui
->flag_b
= mg_create_flagbutton (_("Ban List"), box
, "B");
2112 gui
->flag_k
= mg_create_flagbutton (_("Keyword"), box
, "K");
2113 gui
->key_entry
= gtk_entry_new ();
2114 gtk_widget_set_name (gui
->key_entry
, "xchat-inputbox");
2115 gtk_entry_set_max_length (GTK_ENTRY (gui
->key_entry
), 16);
2116 gtk_widget_set_size_request (gui
->key_entry
, 30, -1);
2117 gtk_box_pack_start (GTK_BOX (box
), gui
->key_entry
, 0, 0, 0);
2118 g_signal_connect (G_OBJECT (gui
->key_entry
), "activate",
2119 G_CALLBACK (mg_key_entry_cb
), NULL
);
2121 if (prefs
.style_inputbox
)
2122 mg_apply_entry_style (gui
->key_entry
);
2124 gui
->flag_l
= mg_create_flagbutton (_("User Limit"), box
, "L");
2125 gui
->limit_entry
= gtk_entry_new ();
2126 gtk_widget_set_name (gui
->limit_entry
, "xchat-inputbox");
2127 gtk_entry_set_max_length (GTK_ENTRY (gui
->limit_entry
), 10);
2128 gtk_widget_set_size_request (gui
->limit_entry
, 30, -1);
2129 gtk_box_pack_start (GTK_BOX (box
), gui
->limit_entry
, 0, 0, 0);
2130 g_signal_connect (G_OBJECT (gui
->limit_entry
), "activate",
2131 G_CALLBACK (mg_limit_entry_cb
), NULL
);
2133 if (prefs
.style_inputbox
)
2134 mg_apply_entry_style (gui
->limit_entry
);
2138 mg_create_link_buttons (GtkWidget *box, gpointer userdata)
2140 gtkutil_button (box, GTK_STOCK_CLOSE, _("Close this tab/window"),
2141 mg_x_click_cb, userdata, 0);
2144 gtkutil_button (box, GTK_STOCK_REDO, _("Attach/Detach this tab"),
2145 mg_link_cb, userdata, 0);
2149 mg_dialog_button_cb (GtkWidget
*wid
, char *cmd
)
2151 /* the longest cmd is 12, and the longest nickname is 64 */
2159 topic
= (char *)(GTK_ENTRY (current_sess
->gui
->topic_entry
)->text
);
2160 topic
= strrchr (topic
, '@');
2164 auto_insert (buf
, sizeof (buf
), cmd
, 0, 0, "", "", "",
2165 server_get_network (current_sess
->server
, TRUE
), host
, "",
2166 current_sess
->channel
);
2168 handle_command (current_sess
, buf
, TRUE
);
2170 /* dirty trick to avoid auto-selection */
2171 SPELL_ENTRY_SET_EDITABLE (current_sess
->gui
->input_box
, FALSE
);
2172 gtk_widget_grab_focus (current_sess
->gui
->input_box
);
2173 SPELL_ENTRY_SET_EDITABLE (current_sess
->gui
->input_box
, TRUE
);
2177 mg_dialog_button (GtkWidget
*box
, char *name
, char *cmd
)
2181 wid
= gtk_button_new_with_label (name
);
2182 gtk_box_pack_start (GTK_BOX (box
), wid
, FALSE
, FALSE
, 0);
2183 g_signal_connect (G_OBJECT (wid
), "clicked",
2184 G_CALLBACK (mg_dialog_button_cb
), cmd
);
2185 gtk_widget_set_size_request (wid
, -1, 0);
2189 mg_create_dialogbuttons (GtkWidget
*box
)
2192 GSList
*list
= dlgbutton_list
;
2198 mg_dialog_button (box
, pop
->name
, pop
->cmd
);
2204 mg_create_topicbar (session
*sess
, GtkWidget
*box
)
2206 GtkWidget
*hbox
, *topic
, *bbox
;
2207 session_gui
*gui
= sess
->gui
;
2209 gui
->topic_bar
= hbox
= gtk_hbox_new (FALSE
, 0);
2210 gtk_box_pack_start (GTK_BOX (box
), hbox
, 0, 0, 0);
2213 sess
->res
->tab
= NULL
;
2215 gui
->topic_entry
= topic
= gtk_entry_new ();
2216 gtk_widget_set_name (topic
, "xchat-inputbox");
2217 gtk_container_add (GTK_CONTAINER (hbox
), topic
);
2218 g_signal_connect (G_OBJECT (topic
), "activate",
2219 G_CALLBACK (mg_topic_cb
), 0);
2221 if (prefs
.style_inputbox
)
2222 mg_apply_entry_style (topic
);
2224 gui
->topicbutton_box
= bbox
= gtk_hbox_new (FALSE
, 0);
2225 gtk_box_pack_start (GTK_BOX (hbox
), bbox
, 0, 0, 0);
2226 mg_create_chanmodebuttons (gui
, bbox
);
2228 gui
->dialogbutton_box
= bbox
= gtk_hbox_new (FALSE
, 0);
2229 gtk_box_pack_start (GTK_BOX (hbox
), bbox
, 0, 0, 0);
2230 mg_create_dialogbuttons (bbox
);
2232 if (!prefs
.paned_userlist
)
2233 gtkutil_button (hbox
, GTK_STOCK_GOTO_LAST
, _("Show/Hide userlist"),
2234 mg_userlist_toggle_cb
, 0, 0);
2237 /* check if a word is clickable */
2240 mg_word_check (GtkWidget
* xtext
, char *word
, int len
)
2242 session
*sess
= current_sess
;
2245 ret
= url_check_word (word
, len
); /* common/url.c */
2248 if (( (word
[0]=='@' || word
[0]=='+' || word
[0]=='%') && userlist_find (sess
, word
+1)) || userlist_find (sess
, word
))
2251 if (sess
->type
== SESS_DIALOG
)
2258 /* mouse click inside text area */
2261 mg_word_clicked (GtkWidget
*xtext
, char *word
, GdkEventButton
*even
)
2263 session
*sess
= current_sess
;
2265 if (even
->button
== 1) /* left button */
2273 if ((even
->state
& 13) == prefs
.gui_url_mod
)
2275 switch (mg_word_check (xtext
, word
, strlen (word
)))
2285 if (even
->button
== 2)
2287 if (sess
->type
== SESS_DIALOG
)
2288 menu_middlemenu (sess
, even
);
2289 else if (even
->type
== GDK_2BUTTON_PRESS
)
2290 userlist_select (sess
, word
);
2294 switch (mg_word_check (xtext
, word
, strlen (word
)))
2297 menu_middlemenu (sess
, even
);
2301 menu_urlmenu (even
, word
);
2304 menu_nickmenu (sess
, even
, (word
[0]=='@' || word
[0]=='+' || word
[0]=='%') ?
2305 word
+1 : word
, FALSE
);
2308 if (*word
== '@' || *word
== '+' || *word
=='^' || *word
=='%' || *word
=='*')
2310 menu_chanmenu (sess
, even
, word
);
2314 char *newword
= malloc (strlen (word
) + 10);
2317 sprintf (newword
, "mailto:%s", word
);
2318 menu_urlmenu (even
, newword
);
2323 menu_nickmenu (sess
, even
, sess
->channel
, FALSE
);
2329 mg_update_xtext (GtkWidget
*wid
)
2331 GtkXText
*xtext
= GTK_XTEXT (wid
);
2333 gtk_xtext_set_palette (xtext
, colors
);
2334 gtk_xtext_set_max_lines (xtext
, prefs
.max_lines
);
2335 gtk_xtext_set_tint (xtext
, prefs
.tint_red
, prefs
.tint_green
, prefs
.tint_blue
);
2336 gtk_xtext_set_background (xtext
, channelwin_pix
, prefs
.transparent
);
2337 gtk_xtext_set_wordwrap (xtext
, prefs
.wordwrap
);
2338 gtk_xtext_set_show_marker (xtext
, prefs
.show_marker
);
2339 gtk_xtext_set_show_separator (xtext
, prefs
.indent_nicks
? prefs
.show_separator
: 0);
2340 gtk_xtext_set_indent (xtext
, prefs
.indent_nicks
);
2341 if (!gtk_xtext_set_font (xtext
, prefs
.font_normal
))
2343 fe_message ("Failed to open any font. I'm out of here!", FE_MSG_WAIT
| FE_MSG_ERROR
);
2347 gtk_xtext_refresh (xtext
, FALSE
);
2350 /* handle errors reported by xtext */
2353 mg_xtext_error (int type
)
2358 fe_message (_("Unable to set transparent background!\n\n"
2359 "You may be using a non-compliant window\n"
2360 "manager that is not currently supported.\n"), FE_MSG_WARN
);
2361 prefs
.transparent
= 0;
2362 /* no others exist yet */
2367 mg_create_textarea (session
*sess
, GtkWidget
*box
)
2369 GtkWidget
*inbox
, *vbox
, *frame
;
2371 session_gui
*gui
= sess
->gui
;
2372 static const GtkTargetEntry dnd_targets
[] =
2374 {"text/uri-list", 0, 1}
2376 static const GtkTargetEntry dnd_dest_targets
[] =
2378 {"XCHAT_CHANVIEW", GTK_TARGET_SAME_APP
, 75 },
2379 {"XCHAT_USERLIST", GTK_TARGET_SAME_APP
, 75 }
2382 vbox
= gtk_vbox_new (FALSE
, 0);
2383 gtk_container_add (GTK_CONTAINER (box
), vbox
);
2385 inbox
= gtk_hbox_new (FALSE
, SCROLLBAR_SPACING
);
2386 gtk_container_add (GTK_CONTAINER (vbox
), inbox
);
2388 frame
= gtk_frame_new (NULL
);
2389 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_IN
);
2390 gtk_container_add (GTK_CONTAINER (inbox
), frame
);
2392 gui
->xtext
= gtk_xtext_new (colors
, TRUE
);
2393 xtext
= GTK_XTEXT (gui
->xtext
);
2394 gtk_xtext_set_max_indent (xtext
, prefs
.max_auto_indent
);
2395 gtk_xtext_set_thin_separator (xtext
, prefs
.thin_separator
);
2396 gtk_xtext_set_error_function (xtext
, mg_xtext_error
);
2397 gtk_xtext_set_urlcheck_function (xtext
, mg_word_check
);
2398 gtk_xtext_set_max_lines (xtext
, prefs
.max_lines
);
2399 gtk_container_add (GTK_CONTAINER (frame
), GTK_WIDGET (xtext
));
2400 mg_update_xtext (GTK_WIDGET (xtext
));
2402 g_signal_connect (G_OBJECT (xtext
), "word_click",
2403 G_CALLBACK (mg_word_clicked
), NULL
);
2405 gui
->vscrollbar
= gtk_vscrollbar_new (GTK_XTEXT (xtext
)->adj
);
2406 gtk_box_pack_start (GTK_BOX (inbox
), gui
->vscrollbar
, FALSE
, TRUE
, 0);
2407 gtk_drag_dest_set (gui
->vscrollbar
, 5, dnd_dest_targets
, 2,
2408 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
);
2409 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_begin",
2410 G_CALLBACK (mg_drag_begin_cb
), NULL
);
2411 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_drop",
2412 G_CALLBACK (mg_drag_drop_cb
), NULL
);
2413 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_motion",
2414 G_CALLBACK (mg_drag_motion_cb
), gui
->vscrollbar
);
2415 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_end",
2416 G_CALLBACK (mg_drag_end_cb
), NULL
);
2418 gtk_drag_dest_set (gui
->xtext
, GTK_DEST_DEFAULT_ALL
, dnd_targets
, 1,
2419 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
);
2420 g_signal_connect (G_OBJECT (gui
->xtext
), "drag_data_received",
2421 G_CALLBACK (mg_dialog_dnd_drop
), NULL
);
2425 mg_create_infoframe (GtkWidget
*box
)
2427 GtkWidget
*frame
, *label
, *hbox
;
2429 frame
= gtk_frame_new (0);
2430 gtk_frame_set_shadow_type ((GtkFrame
*)frame
, GTK_SHADOW_OUT
);
2431 gtk_container_add (GTK_CONTAINER (box
), frame
);
2433 hbox
= gtk_hbox_new (0, 0);
2434 gtk_container_add (GTK_CONTAINER (frame
), hbox
);
2436 label
= gtk_label_new (NULL
);
2437 gtk_container_add (GTK_CONTAINER (hbox
), label
);
2443 mg_create_meters (session_gui
*gui
, GtkWidget
*parent_box
)
2445 GtkWidget
*infbox
, *wid
, *box
;
2447 gui
->meter_box
= infbox
= box
= gtk_vbox_new (0, 1);
2448 gtk_box_pack_start (GTK_BOX (parent_box
), box
, 0, 0, 0);
2450 if ((prefs
.lagometer
& 2) || (prefs
.throttlemeter
& 2))
2452 infbox
= gtk_hbox_new (0, 0);
2453 gtk_box_pack_start (GTK_BOX (box
), infbox
, 0, 0, 0);
2456 if (prefs
.lagometer
& 1)
2458 gui
->lagometer
= wid
= gtk_progress_bar_new ();
2459 gtk_widget_set_size_request (wid
, 1, 8);
2461 wid
= gtk_event_box_new ();
2462 gtk_container_add (GTK_CONTAINER (wid
), gui
->lagometer
);
2463 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2465 if (prefs
.lagometer
& 2)
2467 gui
->laginfo
= wid
= mg_create_infoframe (infbox
);
2468 gtk_label_set_text ((GtkLabel
*) wid
, "Lag");
2471 if (prefs
.throttlemeter
& 1)
2473 gui
->throttlemeter
= wid
= gtk_progress_bar_new ();
2474 gtk_widget_set_size_request (wid
, 1, 8);
2476 wid
= gtk_event_box_new ();
2477 gtk_container_add (GTK_CONTAINER (wid
), gui
->throttlemeter
);
2478 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2480 if (prefs
.throttlemeter
& 2)
2482 gui
->throttleinfo
= wid
= mg_create_infoframe (infbox
);
2483 gtk_label_set_text ((GtkLabel
*) wid
, "Throttle");
2488 mg_update_meters (session_gui
*gui
)
2490 gtk_widget_destroy (gui
->meter_box
);
2491 gui
->lagometer
= NULL
;
2492 gui
->laginfo
= NULL
;
2493 gui
->throttlemeter
= NULL
;
2494 gui
->throttleinfo
= NULL
;
2496 mg_create_meters (gui
, gui
->button_box_parent
);
2497 gtk_widget_show_all (gui
->meter_box
);
2501 mg_create_userlist (session_gui
*gui
, GtkWidget
*box
)
2503 GtkWidget
*frame
, *ulist
, *vbox
;
2505 vbox
= gtk_vbox_new (0, 1);
2506 gtk_container_add (GTK_CONTAINER (box
), vbox
);
2508 frame
= gtk_frame_new (NULL
);
2509 if (!(prefs
.gui_tweaks
& 1))
2510 gtk_box_pack_start (GTK_BOX (vbox
), frame
, 0, 0, GUI_SPACING
);
2512 gui
->namelistinfo
= gtk_label_new (NULL
);
2513 gtk_container_add (GTK_CONTAINER (frame
), gui
->namelistinfo
);
2515 gui
->user_tree
= ulist
= userlist_create (vbox
);
2517 if (prefs
.style_namelistgad
)
2519 gtk_widget_set_style (ulist
, input_style
);
2520 gtk_widget_modify_base (ulist
, GTK_STATE_NORMAL
, &colors
[COL_BG
]);
2523 mg_create_meters (gui
, vbox
);
2525 gui
->button_box_parent
= vbox
;
2526 gui
->button_box
= mg_create_userlistbuttons (vbox
);
2530 mg_leftpane_cb (GtkPaned
*pane
, GParamSpec
*param
, session_gui
*gui
)
2532 prefs
.gui_pane_left_size
= gtk_paned_get_position (pane
);
2536 mg_rightpane_cb (GtkPaned
*pane
, GParamSpec
*param
, session_gui
*gui
)
2540 /* if (pane->child1 == NULL || (!GTK_WIDGET_VISIBLE (pane->child1)))
2542 if (pane->child2 == NULL || (!GTK_WIDGET_VISIBLE (pane->child2)))
2545 gtk_widget_style_get (GTK_WIDGET (pane
), "handle-size", &handle_size
, NULL
);
2546 /* record the position from the RIGHT side */
2547 prefs
.gui_pane_right_size
= GTK_WIDGET (pane
)->allocation
.width
- gtk_paned_get_position (pane
) - handle_size
;
2551 mg_add_pane_signals (session_gui
*gui
)
2553 g_signal_connect (G_OBJECT (gui
->hpane_right
), "notify::position",
2554 G_CALLBACK (mg_rightpane_cb
), gui
);
2555 g_signal_connect (G_OBJECT (gui
->hpane_left
), "notify::position",
2556 G_CALLBACK (mg_leftpane_cb
), gui
);
2561 mg_create_center (session
*sess
, session_gui
*gui
, GtkWidget
*box
)
2563 GtkWidget
*vbox
, *hbox
, *book
;
2565 /* sep between top and bottom of left side */
2566 gui
->vpane_left
= gtk_vpaned_new ();
2568 /* sep between top and bottom of right side */
2569 gui
->vpane_right
= gtk_vpaned_new ();
2571 /* sep between left and xtext */
2572 gui
->hpane_left
= gtk_hpaned_new ();
2573 gtk_paned_set_position (GTK_PANED (gui
->hpane_left
), prefs
.gui_pane_left_size
);
2575 /* sep between xtext and right side */
2576 gui
->hpane_right
= gtk_hpaned_new ();
2578 if (prefs
.gui_tweaks
& 4)
2580 gtk_paned_pack2 (GTK_PANED (gui
->hpane_left
), gui
->vpane_left
, FALSE
, TRUE
);
2581 gtk_paned_pack1 (GTK_PANED (gui
->hpane_left
), gui
->hpane_right
, TRUE
, TRUE
);
2585 gtk_paned_pack1 (GTK_PANED (gui
->hpane_left
), gui
->vpane_left
, FALSE
, TRUE
);
2586 gtk_paned_pack2 (GTK_PANED (gui
->hpane_left
), gui
->hpane_right
, TRUE
, TRUE
);
2588 gtk_paned_pack2 (GTK_PANED (gui
->hpane_right
), gui
->vpane_right
, FALSE
, TRUE
);
2590 gtk_container_add (GTK_CONTAINER (box
), gui
->hpane_left
);
2592 gui
->note_book
= book
= gtk_notebook_new ();
2593 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book
), FALSE
);
2594 gtk_notebook_set_show_border (GTK_NOTEBOOK (book
), FALSE
);
2595 gtk_paned_pack1 (GTK_PANED (gui
->hpane_right
), book
, TRUE
, TRUE
);
2597 hbox
= gtk_hbox_new (FALSE
, 0);
2598 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), hbox
, FALSE
, TRUE
);
2599 mg_create_userlist (gui
, hbox
);
2601 gui
->user_box
= hbox
;
2603 vbox
= gtk_vbox_new (FALSE
, 3);
2604 gtk_notebook_append_page (GTK_NOTEBOOK (book
), vbox
, NULL
);
2605 mg_create_topicbar (sess
, vbox
);
2606 mg_create_textarea (sess
, vbox
);
2607 mg_create_entry (sess
, vbox
);
2609 g_idle_add ((GSourceFunc
)mg_add_pane_signals
, gui
);
2613 mg_change_nick (int cancel
, char *text
, gpointer userdata
)
2619 snprintf (buf
, sizeof (buf
), "nick %s", text
);
2620 handle_command (current_sess
, buf
, FALSE
);
2625 mg_nickclick_cb (GtkWidget
*button
, gpointer userdata
)
2627 fe_get_str (_("Enter new nickname:"), current_sess
->server
->nick
,
2628 mg_change_nick
, NULL
);
2631 /* make sure chanview and userlist positions are sane */
2634 mg_sanitize_positions (int *cv
, int *ul
)
2636 if (prefs
.tab_layout
== 2)
2638 /* treeview can't be on TOP or BOTTOM */
2639 if (*cv
== POS_TOP
|| *cv
== POS_BOTTOM
)
2643 /* userlist can't be on TOP or BOTTOM */
2644 if (*ul
== POS_TOP
|| *ul
== POS_BOTTOM
)
2647 /* can't have both in the same place */
2651 if (*ul
== POS_TOPRIGHT
)
2652 *cv
= POS_BOTTOMRIGHT
;
2657 mg_place_userlist_and_chanview_real (session_gui
*gui
, GtkWidget
*userlist
, GtkWidget
*chanview
)
2659 int unref_userlist
= FALSE
;
2660 int unref_chanview
= FALSE
;
2662 /* first, remove userlist/treeview from their containers */
2663 if (userlist
&& userlist
->parent
)
2665 g_object_ref (userlist
);
2666 gtk_container_remove (GTK_CONTAINER (userlist
->parent
), userlist
);
2667 unref_userlist
= TRUE
;
2670 if (chanview
&& chanview
->parent
)
2672 g_object_ref (chanview
);
2673 gtk_container_remove (GTK_CONTAINER (chanview
->parent
), chanview
);
2674 unref_chanview
= TRUE
;
2679 /* incase the previous pos was POS_HIDDEN */
2680 gtk_widget_show (chanview
);
2682 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 1, 0);
2683 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 2, 2);
2685 /* then place them back in their new positions */
2686 switch (prefs
.tab_pos
)
2689 gtk_paned_pack1 (GTK_PANED (gui
->vpane_left
), chanview
, FALSE
, TRUE
);
2691 case POS_BOTTOMLEFT
:
2692 gtk_paned_pack2 (GTK_PANED (gui
->vpane_left
), chanview
, FALSE
, TRUE
);
2695 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), chanview
, FALSE
, TRUE
);
2697 case POS_BOTTOMRIGHT
:
2698 gtk_paned_pack2 (GTK_PANED (gui
->vpane_right
), chanview
, FALSE
, TRUE
);
2701 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 1, GUI_SPACING
-1);
2702 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2703 1, 2, 1, 2, GTK_FILL
, GTK_FILL
, 0, 0);
2706 gtk_widget_hide (chanview
);
2707 /* always attach it to something to avoid ref_count=0 */
2708 if (prefs
.gui_ulist_pos
== POS_TOP
)
2709 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2710 1, 2, 3, 4, GTK_FILL
, GTK_FILL
, 0, 0);
2713 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2714 1, 2, 1, 2, GTK_FILL
, GTK_FILL
, 0, 0);
2716 default:/* POS_BOTTOM */
2717 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 2, 3);
2718 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2719 1, 2, 3, 4, GTK_FILL
, GTK_FILL
, 0, 0);
2725 switch (prefs
.gui_ulist_pos
)
2728 gtk_paned_pack1 (GTK_PANED (gui
->vpane_left
), userlist
, FALSE
, TRUE
);
2730 case POS_BOTTOMLEFT
:
2731 gtk_paned_pack2 (GTK_PANED (gui
->vpane_left
), userlist
, FALSE
, TRUE
);
2733 case POS_BOTTOMRIGHT
:
2734 gtk_paned_pack2 (GTK_PANED (gui
->vpane_right
), userlist
, FALSE
, TRUE
);
2737 break;*/ /* Hide using the VIEW menu instead */
2738 default:/* POS_TOPRIGHT */
2739 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), userlist
, FALSE
, TRUE
);
2744 g_object_unref (chanview
);
2746 g_object_unref (userlist
);
2748 mg_hide_empty_boxes (gui
);
2752 mg_place_userlist_and_chanview (session_gui
*gui
)
2754 GtkOrientation orientation
;
2755 GtkWidget
*chanviewbox
= NULL
;
2758 mg_sanitize_positions (&prefs
.tab_pos
, &prefs
.gui_ulist_pos
);
2762 pos
= prefs
.tab_pos
;
2764 orientation
= chanview_get_orientation (gui
->chanview
);
2765 if ((pos
== POS_BOTTOM
|| pos
== POS_TOP
) && orientation
== GTK_ORIENTATION_VERTICAL
)
2766 chanview_set_orientation (gui
->chanview
, FALSE
);
2767 else if ((pos
== POS_TOPLEFT
|| pos
== POS_BOTTOMLEFT
|| pos
== POS_TOPRIGHT
|| pos
== POS_BOTTOMRIGHT
) && orientation
== GTK_ORIENTATION_HORIZONTAL
)
2768 chanview_set_orientation (gui
->chanview
, TRUE
);
2769 chanviewbox
= chanview_get_box (gui
->chanview
);
2772 mg_place_userlist_and_chanview_real (gui
, gui
->user_box
, chanviewbox
);
2776 mg_change_layout (int type
)
2780 /* put tabs at the bottom */
2781 if (type
== 0 && prefs
.tab_pos
!= POS_BOTTOM
&& prefs
.tab_pos
!= POS_TOP
)
2782 prefs
.tab_pos
= POS_BOTTOM
;
2784 mg_place_userlist_and_chanview (mg_gui
);
2785 chanview_set_impl (mg_gui
->chanview
, type
);
2790 mg_inputbox_rightclick (GtkEntry
*entry
, GtkWidget
*menu
)
2792 mg_create_color_menu (menu
, NULL
);
2796 mg_create_entry (session
*sess
, GtkWidget
*box
)
2798 GtkWidget
*sw
, *hbox
, *but
, *entry
;
2799 session_gui
*gui
= sess
->gui
;
2801 hbox
= gtk_hbox_new (FALSE
, 0);
2802 gtk_box_pack_start (GTK_BOX (box
), hbox
, 0, 0, 0);
2804 gui
->nick_box
= gtk_hbox_new (FALSE
, 0);
2805 gtk_box_pack_start (GTK_BOX (hbox
), gui
->nick_box
, 0, 0, 0);
2807 gui
->nick_label
= but
= gtk_button_new_with_label (sess
->server
->nick
);
2808 gtk_button_set_relief (GTK_BUTTON (but
), GTK_RELIEF_NONE
);
2809 GTK_WIDGET_UNSET_FLAGS (but
, GTK_CAN_FOCUS
);
2810 gtk_box_pack_end (GTK_BOX (gui
->nick_box
), but
, 0, 0, 0);
2811 g_signal_connect (G_OBJECT (but
), "clicked",
2812 G_CALLBACK (mg_nickclick_cb
), NULL
);
2815 gui
->input_box
= entry
= gtk_text_view_new ();
2816 gtk_widget_set_size_request (entry
, 0, 1);
2817 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (entry
), GTK_WRAP_NONE
);
2818 gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (entry
), FALSE
);
2819 if (prefs
.gui_input_spell
)
2820 gtkspell_new_attach (GTK_TEXT_VIEW (entry
), NULL
, NULL
);
2822 sw
= gtk_scrolled_window_new (NULL
, NULL
);
2823 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw
),
2825 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
2828 gtk_container_add (GTK_CONTAINER (sw
), entry
);
2829 gtk_container_add (GTK_CONTAINER (hbox
), sw
);
2832 gui
->input_box
= entry
= sexy_spell_entry_new ();
2833 sexy_spell_entry_set_checked ((SexySpellEntry
*)entry
, prefs
.gui_input_spell
);
2835 gui
->input_box
= entry
= gtk_entry_new ();
2837 gtk_entry_set_max_length (GTK_ENTRY (gui
->input_box
), 2048);
2838 g_signal_connect (G_OBJECT (entry
), "activate",
2839 G_CALLBACK (mg_inputbox_cb
), gui
);
2840 gtk_container_add (GTK_CONTAINER (hbox
), entry
);
2843 gtk_widget_set_name (entry
, "xchat-inputbox");
2844 g_signal_connect (G_OBJECT (entry
), "key_press_event",
2845 G_CALLBACK (key_handle_key_press
), NULL
);
2846 g_signal_connect (G_OBJECT (entry
), "focus_in_event",
2847 G_CALLBACK (mg_inputbox_focus
), gui
);
2848 g_signal_connect (G_OBJECT (entry
), "populate_popup",
2849 G_CALLBACK (mg_inputbox_rightclick
), NULL
);
2850 gtk_widget_grab_focus (entry
);
2852 if (prefs
.style_inputbox
)
2853 mg_apply_entry_style (entry
);
2857 mg_switch_tab_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer ud
)
2867 if (active_tab
!= old
)
2869 if (old
&& current_tab
)
2870 mg_unpopulate (current_tab
);
2873 } else if (old
!= active_tab
)
2875 /* userdata for non-irc tabs is actually the GtkBox */
2876 mg_show_generic_tab (ud
);
2877 if (!mg_is_userlist_and_tree_combined ())
2878 mg_userlist_showhide (current_sess
, FALSE
); /* hide */
2882 /* compare two tabs (for tab sorting function) */
2885 mg_tabs_compare (session
*a
, session
*b
)
2887 /* server tabs always go first */
2888 if (a
->type
== SESS_SERVER
)
2892 if (a
->type
== SESS_CHANNEL
&& b
->type
!= SESS_CHANNEL
)
2894 if (a
->type
!= SESS_CHANNEL
&& b
->type
== SESS_CHANNEL
)
2897 return strcasecmp (a
->channel
, b
->channel
);
2901 mg_create_tabs (session_gui
*gui
)
2903 gboolean use_icons
= FALSE
;
2905 /* if any one of these PNGs exist, the chanview will create
2906 * the extra column for icons. */
2907 if (pix_channel
|| pix_dialog
|| pix_server
|| pix_util
)
2910 gui
->chanview
= chanview_new (prefs
.tab_layout
, prefs
.truncchans
,
2911 prefs
.tab_sort
, use_icons
,
2912 prefs
.style_namelistgad
? input_style
: NULL
);
2913 chanview_set_callbacks (gui
->chanview
, mg_switch_tab_cb
, mg_xbutton_cb
,
2914 mg_tab_contextmenu_cb
, (void *)mg_tabs_compare
);
2915 mg_place_userlist_and_chanview (gui
);
2919 mg_tabwin_focus_cb (GtkWindow
* win
, GdkEventFocus
*event
, gpointer userdata
)
2921 current_sess
= current_tab
;
2924 gtk_xtext_check_marker_visibility (GTK_XTEXT (current_sess
->gui
->xtext
));
2925 plugin_emit_dummy_print (current_sess
, "Focus Window");
2928 unflash_window (GTK_WIDGET (win
));
2934 mg_topwin_focus_cb (GtkWindow
* win
, GdkEventFocus
*event
, session
*sess
)
2936 current_sess
= sess
;
2937 if (!sess
->server
->server_session
)
2938 sess
->server
->server_session
= sess
;
2939 gtk_xtext_check_marker_visibility(GTK_XTEXT (current_sess
->gui
->xtext
));
2941 unflash_window (GTK_WIDGET (win
));
2943 plugin_emit_dummy_print (sess
, "Focus Window");
2948 mg_create_menu (session_gui
*gui
, GtkWidget
*table
, int away_state
)
2950 GtkAccelGroup
*accel_group
;
2952 accel_group
= gtk_accel_group_new ();
2953 gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel (table
)),
2955 g_object_unref (accel_group
);
2957 gui
->menu
= menu_create_main (accel_group
, TRUE
, away_state
, !gui
->is_tab
,
2959 gtk_table_attach (GTK_TABLE (table
), gui
->menu
, 0, 3, 0, 1,
2960 GTK_EXPAND
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
2964 mg_create_irctab (session
*sess
, GtkWidget
*table
)
2967 session_gui
*gui
= sess
->gui
;
2969 vbox
= gtk_vbox_new (FALSE
, 0);
2970 gtk_table_attach (GTK_TABLE (table
), vbox
, 1, 2, 2, 3,
2971 GTK_EXPAND
| GTK_FILL
, GTK_EXPAND
| GTK_FILL
, 0, 0);
2972 mg_create_center (sess
, gui
, vbox
);
2976 mg_create_topwindow (session
*sess
)
2981 if (sess
->type
== SESS_DIALOG
)
2982 win
= gtkutil_window_new ("XChat", NULL
,
2983 prefs
.dialog_width
, prefs
.dialog_height
, 0);
2985 win
= gtkutil_window_new ("XChat", NULL
,
2986 prefs
.mainwindow_width
,
2987 prefs
.mainwindow_height
, 0);
2988 sess
->gui
->window
= win
;
2989 gtk_container_set_border_width (GTK_CONTAINER (win
), GUI_BORDER
);
2991 g_signal_connect (G_OBJECT (win
), "focus_in_event",
2992 G_CALLBACK (mg_topwin_focus_cb
), sess
);
2993 g_signal_connect (G_OBJECT (win
), "destroy",
2994 G_CALLBACK (mg_topdestroy_cb
), sess
);
2995 g_signal_connect (G_OBJECT (win
), "configure_event",
2996 G_CALLBACK (mg_configure_cb
), sess
);
2998 palette_alloc (win
);
3000 table
= gtk_table_new (4, 3, FALSE
);
3001 /* spacing under the menubar */
3002 gtk_table_set_row_spacing (GTK_TABLE (table
), 0, GUI_SPACING
);
3003 /* left and right borders */
3004 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 1);
3005 gtk_table_set_col_spacing (GTK_TABLE (table
), 1, 1);
3006 gtk_container_add (GTK_CONTAINER (win
), table
);
3008 mg_create_irctab (sess
, table
);
3009 mg_create_menu (sess
->gui
, table
, sess
->server
->is_away
);
3011 if (sess
->res
->buffer
== NULL
)
3013 sess
->res
->buffer
= gtk_xtext_buffer_new (GTK_XTEXT (sess
->gui
->xtext
));
3014 gtk_xtext_buffer_show (GTK_XTEXT (sess
->gui
->xtext
), sess
->res
->buffer
, TRUE
);
3015 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
3016 sess
->res
->user_model
= userlist_create_model ();
3019 userlist_show (sess
);
3021 gtk_widget_show_all (table
);
3024 gtk_widget_hide (sess
->gui
->menu
);
3026 if (!prefs
.topicbar
)
3027 gtk_widget_hide (sess
->gui
->topic_bar
);
3029 if (!prefs
.userlistbuttons
)
3030 gtk_widget_hide (sess
->gui
->button_box
);
3032 if (prefs
.gui_tweaks
& 2)
3033 gtk_widget_hide (sess
->gui
->nick_box
);
3035 mg_decide_userlist (sess
, FALSE
);
3037 if (sess
->type
== SESS_DIALOG
)
3039 /* hide the chan-mode buttons */
3040 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3043 gtk_widget_hide (sess
->gui
->dialogbutton_box
);
3045 if (!prefs
.chanmodebuttons
)
3046 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3049 mg_place_userlist_and_chanview (sess
->gui
);
3051 gtk_widget_show (win
);
3055 mg_tabwindow_de_cb (GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
3060 if ((prefs
.gui_tray_flags
& 1) && tray_toggle_visibility (FALSE
))
3063 /* check for remaining toplevel windows */
3068 if (!sess
->gui
->is_tab
)
3073 mg_open_quit_dialog (TRUE
);
3078 mg_create_tabwindow (session
*sess
)
3083 win
= gtkutil_window_new ("XChat", NULL
, prefs
.mainwindow_width
,
3084 prefs
.mainwindow_height
, 0);
3085 sess
->gui
->window
= win
;
3086 gtk_window_move (GTK_WINDOW (win
), prefs
.mainwindow_left
,
3087 prefs
.mainwindow_top
);
3088 if (prefs
.gui_win_state
)
3089 gtk_window_maximize (GTK_WINDOW (win
));
3090 gtk_container_set_border_width (GTK_CONTAINER (win
), GUI_BORDER
);
3092 g_signal_connect (G_OBJECT (win
), "delete_event",
3093 G_CALLBACK (mg_tabwindow_de_cb
), 0);
3094 g_signal_connect (G_OBJECT (win
), "destroy",
3095 G_CALLBACK (mg_tabwindow_kill_cb
), 0);
3096 g_signal_connect (G_OBJECT (win
), "focus_in_event",
3097 G_CALLBACK (mg_tabwin_focus_cb
), NULL
);
3098 g_signal_connect (G_OBJECT (win
), "configure_event",
3099 G_CALLBACK (mg_configure_cb
), NULL
);
3100 g_signal_connect (G_OBJECT (win
), "window_state_event",
3101 G_CALLBACK (mg_windowstate_cb
), NULL
);
3103 palette_alloc (win
);
3105 sess
->gui
->main_table
= table
= gtk_table_new (4, 3, FALSE
);
3106 /* spacing under the menubar */
3107 gtk_table_set_row_spacing (GTK_TABLE (table
), 0, GUI_SPACING
);
3108 /* left and right borders */
3109 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 1);
3110 gtk_table_set_col_spacing (GTK_TABLE (table
), 1, 1);
3111 gtk_container_add (GTK_CONTAINER (win
), table
);
3113 mg_create_irctab (sess
, table
);
3114 mg_create_tabs (sess
->gui
);
3115 mg_create_menu (sess
->gui
, table
, sess
->server
->is_away
);
3119 gtk_widget_show_all (table
);
3122 gtk_widget_hide (sess
->gui
->menu
);
3124 mg_decide_userlist (sess
, FALSE
);
3126 if (!prefs
.topicbar
)
3127 gtk_widget_hide (sess
->gui
->topic_bar
);
3129 if (!prefs
.chanmodebuttons
)
3130 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3132 if (!prefs
.userlistbuttons
)
3133 gtk_widget_hide (sess
->gui
->button_box
);
3135 if (prefs
.gui_tweaks
& 2)
3136 gtk_widget_hide (sess
->gui
->nick_box
);
3138 mg_place_userlist_and_chanview (sess
->gui
);
3140 gtk_widget_show (win
);
3144 mg_apply_setup (void)
3146 GSList
*list
= sess_list
;
3148 int done_main
= FALSE
;
3150 mg_create_tab_colors ();
3155 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
3156 ((xtext_buffer
*)sess
->res
->buffer
)->needs_recalc
= TRUE
;
3157 if (!sess
->gui
->is_tab
|| !done_main
)
3158 mg_place_userlist_and_chanview (sess
->gui
);
3159 if (sess
->gui
->is_tab
)
3166 mg_add_generic_tab (char *name
, char *title
, void *family
, GtkWidget
*box
)
3170 gtk_notebook_append_page (GTK_NOTEBOOK (mg_gui
->note_book
), box
, NULL
);
3171 gtk_widget_show (box
);
3173 ch
= chanview_add (mg_gui
->chanview
, name
, NULL
, box
, TRUE
, TAG_UTIL
, pix_util
);
3174 chan_set_color (ch
, plain_list
);
3175 /* FIXME: memory leak */
3176 g_object_set_data (G_OBJECT (box
), "title", strdup (title
));
3177 g_object_set_data (G_OBJECT (box
), "ch", ch
);
3179 if (prefs
.newtabstofront
)
3186 fe_buttons_update (session
*sess
)
3188 session_gui
*gui
= sess
->gui
;
3190 gtk_widget_destroy (gui
->button_box
);
3191 gui
->button_box
= mg_create_userlistbuttons (gui
->button_box_parent
);
3193 if (prefs
.userlistbuttons
)
3194 gtk_widget_show (sess
->gui
->button_box
);
3196 gtk_widget_hide (sess
->gui
->button_box
);
3200 fe_clear_channel (session
*sess
)
3202 char tbuf
[CHANLEN
+6];
3203 session_gui
*gui
= sess
->gui
;
3205 if (sess
->gui
->is_tab
)
3207 if (sess
->waitchannel
[0])
3209 if (prefs
.truncchans
> 2 && g_utf8_strlen (sess
->waitchannel
, -1) > prefs
.truncchans
)
3211 /* truncate long channel names */
3213 strcpy (tbuf
+ 1, sess
->waitchannel
);
3214 g_utf8_offset_to_pointer(tbuf
, prefs
.truncchans
)[0] = 0;
3215 strcat (tbuf
, "..)");
3218 sprintf (tbuf
, "(%s)", sess
->waitchannel
);
3222 strcpy (tbuf
, _("<none>"));
3223 chan_rename (sess
->res
->tab
, tbuf
, prefs
.truncchans
);
3226 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3228 gtk_entry_set_text (GTK_ENTRY (gui
->topic_entry
), "");
3232 gtk_widget_destroy (gui
->op_xpm
);
3237 if (sess
->res
->topic_text
)
3239 free (sess
->res
->topic_text
);
3240 sess
->res
->topic_text
= NULL
;
3246 fe_set_nonchannel (session
*sess
, int state
)
3251 fe_dlgbuttons_update (session
*sess
)
3254 session_gui
*gui
= sess
->gui
;
3256 gtk_widget_destroy (gui
->dialogbutton_box
);
3258 gui
->dialogbutton_box
= box
= gtk_hbox_new (0, 0);
3259 gtk_box_pack_start (GTK_BOX (gui
->topic_bar
), box
, 0, 0, 0);
3260 gtk_box_reorder_child (GTK_BOX (gui
->topic_bar
), box
, 3);
3261 mg_create_dialogbuttons (box
);
3263 gtk_widget_show_all (box
);
3265 if (current_tab
&& current_tab
->type
!= SESS_DIALOG
)
3266 gtk_widget_hide (current_tab
->gui
->dialogbutton_box
);
3270 fe_update_mode_buttons (session
*sess
, char mode
, char sign
)
3279 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
3281 if (chan_flags
[i
] == mode
)
3283 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3285 ignore_chanmode
= TRUE
;
3286 if (GTK_TOGGLE_BUTTON (sess
->gui
->flag_wid
[i
])->active
!= state
)
3287 gtk_toggle_button_set_active (
3288 GTK_TOGGLE_BUTTON (sess
->gui
->flag_wid
[i
]), state
);
3289 ignore_chanmode
= FALSE
;
3292 sess
->res
->flag_wid_state
[i
] = state
;
3300 fe_set_nick (server
*serv
, char *newnick
)
3302 GSList
*list
= sess_list
;
3308 if (sess
->server
== serv
)
3310 if (current_tab
== sess
|| !sess
->gui
->is_tab
)
3311 gtk_button_set_label (GTK_BUTTON (sess
->gui
->nick_label
), newnick
);
3318 fe_set_away (server
*serv
)
3320 GSList
*list
= sess_list
;
3326 if (sess
->server
== serv
)
3328 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3330 GTK_CHECK_MENU_ITEM (sess
->gui
->menu_item
[MENU_ID_AWAY
])->active
= serv
->is_away
;
3331 /* gray out my nickname */
3332 mg_set_myself_away (sess
->gui
, serv
->is_away
);
3340 fe_set_channel (session
*sess
)
3342 if (sess
->res
->tab
!= NULL
)
3343 chan_rename (sess
->res
->tab
, sess
->channel
, prefs
.truncchans
);
3347 mg_changui_new (session
*sess
, restore_gui
*res
, int tab
, int focus
)
3349 int first_run
= FALSE
;
3351 struct User
*user
= NULL
;
3355 res
= malloc (sizeof (restore_gui
));
3356 memset (res
, 0, sizeof (restore_gui
));
3361 if (!sess
->server
->front_session
)
3362 sess
->server
->front_session
= sess
;
3364 if (!is_channel (sess
->server
, sess
->channel
))
3365 user
= userlist_find_global (sess
->server
, sess
->channel
);
3369 gui
= malloc (sizeof (session_gui
));
3370 memset (gui
, 0, sizeof (session_gui
));
3371 gui
->is_tab
= FALSE
;
3373 mg_create_topwindow (sess
);
3374 fe_set_title (sess
);
3375 if (user
&& user
->hostname
)
3376 set_topic (sess
, user
->hostname
, user
->hostname
);
3383 gui
= &static_mg_gui
;
3384 memset (gui
, 0, sizeof (session_gui
));
3387 mg_create_tabwindow (sess
);
3389 parent_window
= gui
->window
;
3392 sess
->gui
= gui
= mg_gui
;
3396 if (user
&& user
->hostname
)
3397 set_topic (sess
, user
->hostname
, user
->hostname
);
3401 if (first_run
|| (prefs
.newtabstofront
== FOCUS_NEW_ONLY_ASKED
&& focus
)
3402 || prefs
.newtabstofront
== FOCUS_NEW_ALL
)
3403 chan_focus (res
->tab
);
3407 mg_create_generic_tab (char *name
, char *title
, int force_toplevel
,
3409 void *close_callback
, void *userdata
,
3410 int width
, int height
, GtkWidget
**vbox_ret
,
3413 GtkWidget
*vbox
, *win
;
3415 if (prefs
.tab_pos
== POS_HIDDEN
&& prefs
.windows_as_tabs
)
3416 prefs
.windows_as_tabs
= 0;
3418 if (force_toplevel
|| !prefs
.windows_as_tabs
)
3420 win
= gtkutil_window_new (title
, name
, width
, height
, 3);
3421 vbox
= gtk_vbox_new (0, 0);
3423 gtk_container_add (GTK_CONTAINER (win
), vbox
);
3424 gtk_widget_show (vbox
);
3426 g_signal_connect (G_OBJECT (win
), "destroy",
3427 G_CALLBACK (close_callback
), userdata
);
3431 vbox
= gtk_vbox_new (0, 2);
3432 g_object_set_data (G_OBJECT (vbox
), "w", GINT_TO_POINTER (width
));
3433 g_object_set_data (G_OBJECT (vbox
), "h", GINT_TO_POINTER (height
));
3434 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 3);
3438 g_signal_connect (G_OBJECT (vbox
), "destroy",
3439 G_CALLBACK (close_callback
), userdata
);
3441 mg_add_generic_tab (name
, title
, family
, vbox
);
3443 /* if (link_buttons)
3445 hbox = gtk_hbox_new (FALSE, 0);
3446 gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 0);
3447 mg_create_link_buttons (hbox, ch);
3448 gtk_widget_show (hbox);
3455 mg_move_tab (session
*sess
, int delta
)
3457 if (sess
->gui
->is_tab
)
3458 chan_move (sess
->res
->tab
, delta
);
3462 mg_move_tab_family (session
*sess
, int delta
)
3464 if (sess
->gui
->is_tab
)
3465 chan_move_family (sess
->res
->tab
, delta
);
3469 mg_set_title (GtkWidget
*vbox
, char *title
) /* for non-irc tab/window only */
3473 old
= g_object_get_data (G_OBJECT (vbox
), "title");
3476 g_object_set_data (G_OBJECT (vbox
), "title", strdup (title
));
3480 gtk_window_set_title (GTK_WINDOW (vbox
), title
);
3485 fe_server_callback (server
*serv
)
3489 if (serv
->gui
->chanlist_window
)
3490 mg_close_gen (NULL
, serv
->gui
->chanlist_window
);
3492 if (serv
->gui
->rawlog_window
)
3493 mg_close_gen (NULL
, serv
->gui
->rawlog_window
);
3498 /* called when a session is being killed */
3501 fe_session_callback (session
*sess
)
3503 if (sess
->res
->banlist_window
)
3504 mg_close_gen (NULL
, sess
->res
->banlist_window
);
3506 if (sess
->res
->input_text
)
3507 free (sess
->res
->input_text
);
3509 if (sess
->res
->topic_text
)
3510 free (sess
->res
->topic_text
);
3512 if (sess
->res
->limit_text
)
3513 free (sess
->res
->limit_text
);
3515 if (sess
->res
->key_text
)
3516 free (sess
->res
->key_text
);
3518 if (sess
->res
->queue_text
)
3519 free (sess
->res
->queue_text
);
3520 if (sess
->res
->queue_tip
)
3521 free (sess
->res
->queue_tip
);
3523 if (sess
->res
->lag_text
)
3524 free (sess
->res
->lag_text
);
3525 if (sess
->res
->lag_tip
)
3526 free (sess
->res
->lag_tip
);
3528 if (sess
->gui
->bartag
)
3529 fe_timeout_remove (sess
->gui
->bartag
);
3531 if (sess
->gui
!= &static_mg_gui
)
3536 /* ===== DRAG AND DROP STUFF ===== */
3539 is_child_of (GtkWidget
*widget
, GtkWidget
*parent
)
3543 if (widget
->parent
== parent
)
3545 widget
= widget
->parent
;
3551 mg_handle_drop (GtkWidget
*widget
, int y
, int *pos
, int *other_pos
)
3554 session_gui
*gui
= current_sess
->gui
;
3556 gdk_drawable_get_size (widget
->window
, NULL
, &height
);
3560 if (is_child_of (widget
, gui
->vpane_left
))
3561 *pos
= 1; /* top left */
3563 *pos
= 3; /* top right */
3567 if (is_child_of (widget
, gui
->vpane_left
))
3568 *pos
= 2; /* bottom left */
3570 *pos
= 4; /* bottom right */
3573 /* both in the same pos? must move one */
3574 if (*pos
== *other_pos
)
3593 mg_place_userlist_and_chanview (gui
);
3597 mg_is_gui_target (GdkDragContext
*context
)
3601 if (!context
|| !context
->targets
|| !context
->targets
->data
)
3604 target_name
= gdk_atom_name (context
->targets
->data
);
3607 /* if it's not XCHAT_CHANVIEW or XCHAT_USERLIST */
3608 /* we should ignore it. */
3609 if (target_name
[0] != 'X')
3611 g_free (target_name
);
3614 g_free (target_name
);
3620 /* this begin callback just creates an nice of the source */
3623 mg_drag_begin_cb (GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
3627 GdkPixbuf
*pix
, *pix2
;
3629 /* ignore file drops */
3630 if (!mg_is_gui_target (context
))
3633 cmap
= gtk_widget_get_colormap (widget
);
3634 gdk_drawable_get_size (widget
->window
, &width
, &height
);
3636 pix
= gdk_pixbuf_get_from_drawable (NULL
, widget
->window
, cmap
, 0, 0, 0, 0, width
, height
);
3637 pix2
= gdk_pixbuf_scale_simple (pix
, width
* 4 / 5, height
/ 2, GDK_INTERP_HYPER
);
3638 g_object_unref (pix
);
3640 gtk_drag_set_icon_pixbuf (context
, pix2
, 0, 0);
3641 g_object_set_data (G_OBJECT (widget
), "ico", pix2
);
3647 mg_drag_end_cb (GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
3649 /* ignore file drops */
3650 if (!mg_is_gui_target (context
))
3653 g_object_unref (g_object_get_data (G_OBJECT (widget
), "ico"));
3659 mg_drag_drop_cb (GtkWidget
*widget
, GdkDragContext
*context
, int x
, int y
, guint time
, gpointer user_data
)
3661 /* ignore file drops */
3662 if (!mg_is_gui_target (context
))
3665 switch (context
->action
)
3667 case GDK_ACTION_MOVE
:
3669 mg_handle_drop (widget
, y
, &prefs
.gui_ulist_pos
, &prefs
.tab_pos
);
3671 case GDK_ACTION_COPY
:
3672 /* from tree - we use GDK_ACTION_COPY for the tree */
3673 mg_handle_drop (widget
, y
, &prefs
.tab_pos
, &prefs
.gui_ulist_pos
);
3682 /* draw highlight rectangle in the destination */
3685 mg_drag_motion_cb (GtkWidget
*widget
, GdkDragContext
*context
, int x
, int y
, guint time
, gpointer scbar
)
3690 int half
, width
, height
;
3695 /* ignore file drops */
3696 if (!mg_is_gui_target (context
))
3699 if (scbar
) /* scrollbar */
3701 ox
= widget
->allocation
.x
;
3702 oy
= widget
->allocation
.y
;
3703 width
= widget
->allocation
.width
;
3704 height
= widget
->allocation
.height
;
3705 draw
= widget
->window
;
3710 gdk_drawable_get_size (widget
->window
, &width
, &height
);
3711 draw
= widget
->window
;
3714 val
.subwindow_mode
= GDK_INCLUDE_INFERIORS
;
3715 val
.graphics_exposures
= 0;
3716 val
.function
= GDK_XOR
;
3718 gc
= gdk_gc_new_with_values (widget
->window
, &val
, GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
| GDK_GC_FUNCTION
);
3719 col
.red
= rand() % 0xffff;
3720 col
.green
= rand() % 0xffff;
3721 col
.blue
= rand() % 0xffff;
3722 gdk_colormap_alloc_color (gtk_widget_get_colormap (widget
), &col
, FALSE
, TRUE
);
3723 gdk_gc_set_foreground (gc
, &col
);
3728 /* are both tree/userlist on the same side? */
3729 paned
= (GtkPaned
*)widget
->parent
->parent
;
3730 if (paned
->child1
!= NULL
&& paned
->child2
!= NULL
)
3732 gdk_draw_rectangle (draw
, gc
, 0, 1, 2, width
- 3, height
- 4);
3733 gdk_draw_rectangle (draw
, gc
, 0, 0, 1, width
- 1, height
- 2);
3734 g_object_unref (gc
);
3741 gdk_draw_rectangle (draw
, gc
, FALSE
, 1 + ox
, 2 + oy
, width
- 3, half
- 4);
3742 gdk_draw_rectangle (draw
, gc
, FALSE
, 0 + ox
, 1 + oy
, width
- 1, half
- 2);
3743 gtk_widget_queue_draw_area (widget
, ox
, half
+ oy
, width
, height
- half
);
3747 gdk_draw_rectangle (draw
, gc
, FALSE
, 0 + ox
, half
+ 1 + oy
, width
- 1, half
- 2);
3748 gdk_draw_rectangle (draw
, gc
, FALSE
, 1 + ox
, half
+ 2 + oy
, width
- 3, half
- 4);
3749 gtk_widget_queue_draw_area (widget
, ox
, oy
, width
, half
);
3752 g_object_unref (gc
);