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"
56 #include "../common/text.h"
65 #include "userlistgui.h"
68 #include "plugin-tray.h"
72 #include <gtk/gtktextview.h>
73 #include <gtkspell/gtkspell.h>
77 #include "sexy-spell-entry.h"
80 #define GUI_SPACING (3)
81 #define GUI_BORDER (0)
82 #define SCROLLBAR_SPACING (2)
91 POS_TOP
= 5, /* for tabs only */
96 /* two different types of tabs */
97 #define TAG_IRC 0 /* server, channel, dialog */
98 #define TAG_UTIL 1 /* dcc, notify, chanlist */
100 static void mg_create_entry (session
*sess
, GtkWidget
*box
);
101 static void mg_link_irctab (session
*sess
, int focus
);
103 static session_gui static_mg_gui
;
104 static session_gui
*mg_gui
= NULL
; /* the shared irc tab */
105 static int ignore_chanmode
= FALSE
;
106 static const char chan_flags
[] = { 't', 'n', 's', 'i', 'p', 'm', 'l', 'k' };
108 static chan
*active_tab
= NULL
; /* active tab */
109 GtkWidget
*parent_window
= NULL
; /* the master window */
111 GtkStyle
*input_style
;
113 static PangoAttrList
*away_list
;
114 static PangoAttrList
*newdata_list
;
115 static PangoAttrList
*nickseen_list
;
116 static PangoAttrList
*newmsg_list
;
117 static PangoAttrList
*plain_list
= NULL
;
122 /* use these when it's a GtkTextView instead of GtkEntry */
125 SPELL_ENTRY_GET_TEXT (GtkWidget
*entry
)
127 static char *last
= NULL
; /* warning: don't overlap 2 GET_TEXT calls! */
128 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
129 GtkTextIter start_iter
, end_iter
;
131 gtk_text_buffer_get_iter_at_offset (buf
, &start_iter
, 0);
132 gtk_text_buffer_get_end_iter (buf
, &end_iter
);
134 last
= gtk_text_buffer_get_text (buf
, &start_iter
, &end_iter
, FALSE
);
139 SPELL_ENTRY_SET_POS (GtkWidget
*entry
, int pos
)
142 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
144 gtk_text_buffer_get_iter_at_offset (buf
, &iter
, pos
);
145 gtk_text_buffer_place_cursor (buf
, &iter
);
149 SPELL_ENTRY_GET_POS (GtkWidget
*entry
)
152 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
154 gtk_text_buffer_get_iter_at_mark (buf
, &cursor
, gtk_text_buffer_get_insert (buf
));
155 return gtk_text_iter_get_offset (&cursor
);
159 SPELL_ENTRY_INSERT (GtkWidget
*entry
, const char *text
, int len
, int *pos
)
162 GtkTextBuffer
*buf
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry
));
164 /* len is bytes. pos is chars. */
165 gtk_text_buffer_get_iter_at_offset (buf
, &iter
, *pos
);
166 gtk_text_buffer_insert (buf
, &iter
, text
, len
);
167 *pos
+= g_utf8_strlen (text
, len
);
172 static PangoAttrList
*
173 mg_attr_list_create (GdkColor
*col
, int size
)
175 PangoAttribute
*attr
;
178 list
= pango_attr_list_new ();
182 attr
= pango_attr_foreground_new (col
->red
, col
->green
, col
->blue
);
183 attr
->start_index
= 0;
184 attr
->end_index
= 0xffff;
185 pango_attr_list_insert (list
, attr
);
190 attr
= pango_attr_scale_new (size
== 1 ? PANGO_SCALE_SMALL
: PANGO_SCALE_X_SMALL
);
191 attr
->start_index
= 0;
192 attr
->end_index
= 0xffff;
193 pango_attr_list_insert (list
, attr
);
200 mg_create_tab_colors (void)
204 pango_attr_list_unref (plain_list
);
205 pango_attr_list_unref (newmsg_list
);
206 pango_attr_list_unref (newdata_list
);
207 pango_attr_list_unref (nickseen_list
);
208 pango_attr_list_unref (away_list
);
211 plain_list
= mg_attr_list_create (NULL
, prefs
.tab_small
);
212 newdata_list
= mg_attr_list_create (&colors
[COL_NEW_DATA
], prefs
.tab_small
);
213 nickseen_list
= mg_attr_list_create (&colors
[COL_HILIGHT
], prefs
.tab_small
);
214 newmsg_list
= mg_attr_list_create (&colors
[COL_NEW_MSG
], prefs
.tab_small
);
215 away_list
= mg_attr_list_create (&colors
[COL_AWAY
], FALSE
);
219 #include <gdk/gdkx.h>
222 set_window_urgency (GtkWidget
*win
, gboolean set
)
226 hints
= XGetWMHints(GDK_WINDOW_XDISPLAY(win
->window
), GDK_WINDOW_XWINDOW(win
->window
));
228 hints
->flags
|= XUrgencyHint
;
230 hints
->flags
&= ~XUrgencyHint
;
231 XSetWMHints(GDK_WINDOW_XDISPLAY(win
->window
),
232 GDK_WINDOW_XWINDOW(win
->window
), hints
);
237 flash_window (GtkWidget
*win
)
239 set_window_urgency (win
, TRUE
);
243 unflash_window (GtkWidget
*win
)
245 set_window_urgency (win
, FALSE
);
249 /* flash the taskbar button */
252 fe_flash_window (session
*sess
)
254 #if defined(USE_XLIB)
255 if (fe_gui_info (sess
, 0) != 1) /* only do it if not focused */
256 flash_window (sess
->gui
->window
);
260 /* set a tab plain, red, light-red, or blue */
263 fe_set_tab_color (struct session
*sess
, int col
)
265 struct session
*server_sess
= sess
->server
->server_session
;
266 if (sess
->gui
->is_tab
&& (col
== 0 || sess
!= current_tab
))
270 case 0: /* no particular color (theme default) */
271 sess
->new_data
= FALSE
;
272 sess
->msg_said
= FALSE
;
273 sess
->nick_said
= FALSE
;
274 chan_set_color (sess
->res
->tab
, plain_list
);
276 case 1: /* new data has been displayed (dark red) */
277 sess
->new_data
= TRUE
;
278 sess
->msg_said
= FALSE
;
279 sess
->nick_said
= FALSE
;
280 chan_set_color (sess
->res
->tab
, newdata_list
);
282 if (chan_is_collapsed (sess
->res
->tab
)
283 && !(server_sess
->msg_said
|| server_sess
->nick_said
))
285 server_sess
->new_data
= TRUE
;
286 server_sess
->msg_said
= FALSE
;
287 server_sess
->nick_said
= FALSE
;
288 chan_set_color (chan_get_parent (sess
->res
->tab
), newdata_list
);
292 case 2: /* new message arrived in channel (light red) */
293 sess
->new_data
= FALSE
;
294 sess
->msg_said
= TRUE
;
295 sess
->nick_said
= FALSE
;
296 chan_set_color (sess
->res
->tab
, newmsg_list
);
298 if (chan_is_collapsed (sess
->res
->tab
) && !server_sess
->nick_said
)
300 server_sess
->new_data
= FALSE
;
301 server_sess
->msg_said
= TRUE
;
302 server_sess
->nick_said
= FALSE
;
303 chan_set_color (chan_get_parent (sess
->res
->tab
), newmsg_list
);
307 case 3: /* your nick has been seen (blue) */
308 sess
->new_data
= FALSE
;
309 sess
->msg_said
= FALSE
;
310 sess
->nick_said
= TRUE
;
311 chan_set_color (sess
->res
->tab
, nickseen_list
);
313 if (chan_is_collapsed (sess
->res
->tab
))
315 server_sess
->new_data
= FALSE
;
316 server_sess
->msg_said
= FALSE
;
317 server_sess
->nick_said
= TRUE
;
318 chan_set_color (chan_get_parent (sess
->res
->tab
), nickseen_list
);
327 mg_set_myself_away (session_gui
*gui
, gboolean away
)
329 gtk_label_set_attributes (GTK_LABEL (GTK_BIN (gui
->nick_label
)->child
),
330 away
? away_list
: NULL
);
333 /* change the little icon to the left of your nickname */
336 mg_set_access_icon (session_gui
*gui
, GdkPixbuf
*pix
, gboolean away
)
340 if (pix
== gtk_image_get_pixbuf (GTK_IMAGE (gui
->op_xpm
))) /* no change? */
342 mg_set_myself_away (gui
, away
);
346 gtk_widget_destroy (gui
->op_xpm
);
352 gui
->op_xpm
= gtk_image_new_from_pixbuf (pix
);
353 gtk_box_pack_start (GTK_BOX (gui
->nick_box
), gui
->op_xpm
, 0, 0, 0);
354 gtk_widget_show (gui
->op_xpm
);
357 mg_set_myself_away (gui
, away
);
361 mg_inputbox_focus (GtkWidget
*widget
, GdkEventFocus
*event
, session_gui
*gui
)
373 if (sess
->gui
== gui
)
376 if (!sess
->server
->server_session
)
377 sess
->server
->server_session
= sess
;
387 mg_inputbox_cb (GtkWidget
*igad
, session_gui
*gui
)
390 static int ignore
= FALSE
;
392 session
*sess
= NULL
;
397 cmd
= SPELL_ENTRY_GET_TEXT (igad
);
403 /* avoid recursive loop */
405 SPELL_ENTRY_SET_TEXT (igad
, "");
408 /* where did this event come from? */
418 if (sess
->gui
== gui
)
427 handle_multiline (sess
, cmd
, TRUE
, FALSE
);
433 has_key (char *modes
)
437 /* this is a crude check, but "-k" can't exist, so it works. */
450 fe_set_title (session
*sess
)
455 if (sess
->gui
->is_tab
&& sess
!= current_tab
)
460 if (sess
->server
->connected
== FALSE
&& sess
->type
!= SESS_DIALOG
)
466 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s %s @ %s",
467 _("Dialog with"), sess
->channel
, server_get_network (sess
->server
, TRUE
));
470 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s @ %s",
471 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
));
474 /* don't display keys in the titlebar */
475 if ((!(prefs
.gui_tweaks
& 16)) && has_key (sess
->current_modes
))
476 snprintf (tbuf
, sizeof (tbuf
),
477 DISPLAY_NAME
": %s @ %s / %s",
478 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
),
481 snprintf (tbuf
, sizeof (tbuf
),
482 DISPLAY_NAME
": %s @ %s / %s (%s)",
483 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
),
484 sess
->channel
, sess
->current_modes
? sess
->current_modes
: "");
485 if (prefs
.gui_tweaks
& 1)
486 snprintf (tbuf
+ strlen (tbuf
), 9, " (%d)", sess
->total
);
490 snprintf (tbuf
, sizeof (tbuf
), DISPLAY_NAME
": %s @ %s (notices)",
491 sess
->server
->nick
, server_get_network (sess
->server
, TRUE
));
495 gtk_window_set_title (GTK_WINDOW (sess
->gui
->window
), DISPLAY_NAME
);
499 gtk_window_set_title (GTK_WINDOW (sess
->gui
->window
), tbuf
);
503 mg_windowstate_cb (GtkWindow
*wid
, GdkEventWindowState
*event
, gpointer userdata
)
505 prefs
.gui_win_state
= 0;
506 if (event
->new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
)
507 prefs
.gui_win_state
= 1;
509 if ((event
->changed_mask
& GDK_WINDOW_STATE_ICONIFIED
) &&
510 (event
->new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) &&
511 (prefs
.gui_tray_flags
& 4))
513 tray_toggle_visibility (TRUE
);
514 gtk_window_deiconify (wid
);
521 mg_configure_cb (GtkWidget
*wid
, GdkEventConfigure
*event
, session
*sess
)
523 if (sess
== NULL
) /* for the main_window */
527 if (prefs
.mainwindow_save
)
530 gtk_window_get_position (GTK_WINDOW (wid
), &prefs
.mainwindow_left
,
531 &prefs
.mainwindow_top
);
532 gtk_window_get_size (GTK_WINDOW (wid
), &prefs
.mainwindow_width
,
533 &prefs
.mainwindow_height
);
540 if (sess
->type
== SESS_DIALOG
&& prefs
.mainwindow_save
)
542 gtk_window_get_position (GTK_WINDOW (wid
), &prefs
.dialog_left
,
544 gtk_window_get_size (GTK_WINDOW (wid
), &prefs
.dialog_width
,
545 &prefs
.dialog_height
);
548 if (((GtkXText
*) sess
->gui
->xtext
)->transparent
)
549 gtk_widget_queue_draw (sess
->gui
->xtext
);
555 /* move to a non-irc tab */
558 mg_show_generic_tab (GtkWidget
*box
)
563 #if defined(GTK_WIDGET_HAS_FOCUS)
564 if (current_sess
&& GTK_WIDGET_HAS_FOCUS (current_sess
->gui
->input_box
))
566 if (current_sess
&& gtk_widget_has_focus (current_sess
->gui
->input_box
))
568 f
= current_sess
->gui
->input_box
;
570 num
= gtk_notebook_page_num (GTK_NOTEBOOK (mg_gui
->note_book
), box
);
571 gtk_notebook_set_current_page (GTK_NOTEBOOK (mg_gui
->note_book
), num
);
572 gtk_tree_view_set_model (GTK_TREE_VIEW (mg_gui
->user_tree
), NULL
);
573 gtk_window_set_title (GTK_WINDOW (mg_gui
->window
),
574 g_object_get_data (G_OBJECT (box
), "title"));
575 gtk_widget_set_sensitive (mg_gui
->menu
, FALSE
);
578 gtk_widget_grab_focus (f
);
581 /* a channel has been focused */
584 mg_focus (session
*sess
)
586 if (sess
->gui
->is_tab
)
590 /* dirty trick to avoid auto-selection */
591 SPELL_ENTRY_SET_EDITABLE (sess
->gui
->input_box
, FALSE
);
592 gtk_widget_grab_focus (sess
->gui
->input_box
);
593 SPELL_ENTRY_SET_EDITABLE (sess
->gui
->input_box
, TRUE
);
595 sess
->server
->front_session
= sess
;
597 if (sess
->server
->server_session
!= NULL
)
599 if (sess
->server
->server_session
->type
!= SESS_SERVER
)
600 sess
->server
->server_session
= sess
;
603 sess
->server
->server_session
= sess
;
606 if (sess
->new_data
|| sess
->nick_said
|| sess
->msg_said
)
608 sess
->nick_said
= FALSE
;
609 sess
->msg_said
= FALSE
;
610 sess
->new_data
= FALSE
;
611 /* when called via mg_changui_new, is_tab might be true, but
612 sess->res->tab is still NULL. */
614 fe_set_tab_color (sess
, 0);
619 mg_progressbar_update (GtkWidget
*bar
)
622 static float pos
= 0;
630 gtk_progress_bar_set_orientation ((GtkProgressBar
*) bar
,
631 GTK_PROGRESS_RIGHT_TO_LEFT
);
635 gtk_progress_bar_set_orientation ((GtkProgressBar
*) bar
,
636 GTK_PROGRESS_LEFT_TO_RIGHT
);
640 gtk_progress_bar_set_fraction ((GtkProgressBar
*) bar
, pos
);
645 mg_progressbar_create (session_gui
*gui
)
647 gui
->bar
= gtk_progress_bar_new ();
648 gtk_box_pack_start (GTK_BOX (gui
->nick_box
), gui
->bar
, 0, 0, 0);
649 gtk_widget_show (gui
->bar
);
650 gui
->bartag
= fe_timeout_add (50, mg_progressbar_update
, gui
->bar
);
654 mg_progressbar_destroy (session_gui
*gui
)
656 fe_timeout_remove (gui
->bartag
);
657 gtk_widget_destroy (gui
->bar
);
662 /* switching tabs away from this one, so remember some info about it! */
665 mg_unpopulate (session
*sess
)
674 res
->input_text
= strdup (SPELL_ENTRY_GET_TEXT (gui
->input_box
));
675 res
->topic_text
= strdup (GTK_ENTRY (gui
->topic_entry
)->text
);
676 res
->limit_text
= strdup (GTK_ENTRY (gui
->limit_entry
)->text
);
677 res
->key_text
= strdup (GTK_ENTRY (gui
->key_entry
)->text
);
679 res
->lag_text
= strdup (gtk_label_get_text (GTK_LABEL (gui
->laginfo
)));
680 if (gui
->throttleinfo
)
681 res
->queue_text
= strdup (gtk_label_get_text (GTK_LABEL (gui
->throttleinfo
)));
683 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
684 res
->flag_wid_state
[i
] = GTK_TOGGLE_BUTTON (gui
->flag_wid
[i
])->active
;
686 res
->old_ul_value
= userlist_get_value (gui
->user_tree
);
688 res
->lag_value
= gtk_progress_bar_get_fraction (
689 GTK_PROGRESS_BAR (gui
->lagometer
));
690 if (gui
->throttlemeter
)
691 res
->queue_value
= gtk_progress_bar_get_fraction (
692 GTK_PROGRESS_BAR (gui
->throttlemeter
));
696 res
->c_graph
= TRUE
; /* still have a graph, just not visible now */
697 mg_progressbar_destroy (gui
);
702 mg_restore_label (GtkWidget
*label
, char **text
)
709 gtk_label_set_text (GTK_LABEL (label
), *text
);
714 gtk_label_set_text (GTK_LABEL (label
), "");
719 mg_restore_entry (GtkWidget
*entry
, char **text
)
723 gtk_entry_set_text (GTK_ENTRY (entry
), *text
);
728 gtk_entry_set_text (GTK_ENTRY (entry
), "");
730 gtk_editable_set_position (GTK_EDITABLE (entry
), -1);
734 mg_restore_speller (GtkWidget
*entry
, char **text
)
738 SPELL_ENTRY_SET_TEXT (entry
, *text
);
743 SPELL_ENTRY_SET_TEXT (entry
, "");
745 SPELL_ENTRY_SET_POS (entry
, -1);
749 mg_set_topic_tip (session
*sess
)
758 text
= g_strdup_printf (_("Topic for %s is: %s"), sess
->channel
,
760 add_tip (sess
->gui
->topic_entry
, text
);
763 add_tip (sess
->gui
->topic_entry
, _("No topic is set"));
766 if (GTK_ENTRY (sess
->gui
->topic_entry
)->text
&&
767 GTK_ENTRY (sess
->gui
->topic_entry
)->text
[0])
768 add_tip (sess
->gui
->topic_entry
, GTK_ENTRY (sess
->gui
->topic_entry
)->text
);
770 add_tip (sess
->gui
->topic_entry
, NULL
);
775 mg_hide_empty_pane (GtkPaned
*pane
)
777 #if defined(GTK_WIDGET_VISIBLE)
778 if ((pane
->child1
== NULL
|| !GTK_WIDGET_VISIBLE (pane
->child1
)) &&
779 (pane
->child2
== NULL
|| !GTK_WIDGET_VISIBLE (pane
->child2
)))
781 if ((pane
->child1
== NULL
|| !gtk_widget_get_visible (pane
->child1
)) &&
782 (pane
->child2
== NULL
|| !gtk_widget_get_visible (pane
->child2
)))
785 gtk_widget_hide (GTK_WIDGET (pane
));
789 gtk_widget_show (GTK_WIDGET (pane
));
793 mg_hide_empty_boxes (session_gui
*gui
)
795 /* hide empty vpanes - so the handle is not shown */
796 mg_hide_empty_pane ((GtkPaned
*)gui
->vpane_right
);
797 mg_hide_empty_pane ((GtkPaned
*)gui
->vpane_left
);
801 mg_userlist_showhide (session
*sess
, int show
)
803 session_gui
*gui
= sess
->gui
;
808 gtk_widget_show (gui
->user_box
);
811 gtk_widget_style_get (GTK_WIDGET (gui
->hpane_right
), "handle-size", &handle_size
, NULL
);
812 gtk_paned_set_position (GTK_PANED (gui
->hpane_right
), GTK_WIDGET (gui
->hpane_right
)->allocation
.width
- (prefs
.gui_pane_right_size
+ handle_size
));
816 gtk_widget_hide (gui
->user_box
);
820 mg_hide_empty_boxes (gui
);
824 mg_is_userlist_and_tree_combined (void)
826 if (prefs
.tab_pos
== POS_TOPLEFT
&& prefs
.gui_ulist_pos
== POS_BOTTOMLEFT
)
828 if (prefs
.tab_pos
== POS_BOTTOMLEFT
&& prefs
.gui_ulist_pos
== POS_TOPLEFT
)
831 if (prefs
.tab_pos
== POS_TOPRIGHT
&& prefs
.gui_ulist_pos
== POS_BOTTOMRIGHT
)
833 if (prefs
.tab_pos
== POS_BOTTOMRIGHT
&& prefs
.gui_ulist_pos
== POS_TOPRIGHT
)
839 /* decide if the userlist should be shown or hidden for this tab */
842 mg_decide_userlist (session
*sess
, gboolean switch_to_current
)
844 /* when called from menu.c we need this */
845 if (sess
->gui
== mg_gui
&& switch_to_current
)
848 if (prefs
.hideuserlist
)
850 mg_userlist_showhide (sess
, FALSE
);
860 if (mg_is_userlist_and_tree_combined ())
861 mg_userlist_showhide (sess
, TRUE
); /* show */
863 mg_userlist_showhide (sess
, FALSE
); /* hide */
866 mg_userlist_showhide (sess
, TRUE
); /* show */
871 mg_userlist_toggle_cb (GtkWidget
*button
, gpointer userdata
)
873 prefs
.hideuserlist
= !prefs
.hideuserlist
;
874 mg_decide_userlist (current_sess
, FALSE
);
875 gtk_widget_grab_focus (current_sess
->gui
->input_box
);
878 static int ul_tag
= 0;
881 mg_populate_userlist (session
*sess
)
888 if (is_session (sess
))
891 if (sess
->type
== SESS_DIALOG
)
892 mg_set_access_icon (sess
->gui
, NULL
, sess
->server
->is_away
);
894 mg_set_access_icon (sess
->gui
, get_user_icon (sess
->server
, sess
->me
), sess
->server
->is_away
);
895 userlist_show (sess
);
896 userlist_set_value (sess
->gui
->user_tree
, sess
->res
->old_ul_value
);
903 /* fill the irc tab with a new channel */
906 mg_populate (session
*sess
)
908 session_gui
*gui
= sess
->gui
;
909 restore_gui
*res
= sess
->res
;
910 int i
, render
= TRUE
;
911 guint16 vis
= gui
->ul_hidden
;
916 /* show the dialog buttons */
917 gtk_widget_show (gui
->dialogbutton_box
);
918 /* hide the chan-mode buttons */
919 gtk_widget_hide (gui
->topicbutton_box
);
920 /* hide the userlist */
921 mg_decide_userlist (sess
, FALSE
);
922 /* shouldn't edit the topic */
923 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), FALSE
);
926 if (prefs
.chanmodebuttons
)
927 gtk_widget_show (gui
->topicbutton_box
);
928 /* hide the dialog buttons */
929 gtk_widget_hide (gui
->dialogbutton_box
);
930 /* hide the userlist */
931 mg_decide_userlist (sess
, FALSE
);
932 /* shouldn't edit the topic */
933 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), FALSE
);
936 /* hide the dialog buttons */
937 gtk_widget_hide (gui
->dialogbutton_box
);
938 if (prefs
.chanmodebuttons
)
939 gtk_widget_show (gui
->topicbutton_box
);
940 /* show the userlist */
941 mg_decide_userlist (sess
, FALSE
);
942 /* let the topic be editted */
943 gtk_editable_set_editable (GTK_EDITABLE (gui
->topic_entry
), TRUE
);
946 /* move to THE irc tab */
948 gtk_notebook_set_current_page (GTK_NOTEBOOK (gui
->note_book
), 0);
950 /* xtext size change? Then don't render, wait for the expose caused
951 by showing/hidding the userlist */
952 if (vis
!= gui
->ul_hidden
&& gui
->user_box
->allocation
.width
> 1)
955 gtk_xtext_buffer_show (GTK_XTEXT (gui
->xtext
), res
->buffer
, render
);
958 gtk_widget_set_sensitive (gui
->menu
, TRUE
);
960 /* restore all the GtkEntry's */
961 mg_restore_entry (gui
->topic_entry
, &res
->topic_text
);
962 mg_restore_speller (gui
->input_box
, &res
->input_text
);
963 mg_restore_entry (gui
->key_entry
, &res
->key_text
);
964 mg_restore_entry (gui
->limit_entry
, &res
->limit_text
);
965 mg_restore_label (gui
->laginfo
, &res
->lag_text
);
966 mg_restore_label (gui
->throttleinfo
, &res
->queue_text
);
971 /* this one flickers, so only change if necessary */
972 if (strcmp (sess
->server
->nick
, gtk_button_get_label (GTK_BUTTON (gui
->nick_label
))) != 0)
973 gtk_button_set_label (GTK_BUTTON (gui
->nick_label
), sess
->server
->nick
);
975 /* this is slow, so make it a timeout event */
978 mg_populate_userlist (sess
);
982 ul_tag
= g_idle_add ((GSourceFunc
)mg_populate_userlist
, NULL
);
985 fe_userlist_numbers (sess
);
987 /* restore all the channel mode buttons */
988 ignore_chanmode
= TRUE
;
989 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
990 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gui
->flag_wid
[i
]),
991 res
->flag_wid_state
[i
]);
992 ignore_chanmode
= FALSE
;
996 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui
->lagometer
),
999 add_tip (sess
->gui
->lagometer
->parent
, res
->lag_tip
);
1001 if (gui
->throttlemeter
)
1003 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui
->throttlemeter
),
1006 add_tip (sess
->gui
->throttlemeter
->parent
, res
->queue_tip
);
1009 /* did this tab have a connecting graph? restore it.. */
1012 res
->c_graph
= FALSE
;
1013 mg_progressbar_create (gui
);
1017 GTK_CHECK_MENU_ITEM (gui
->menu_item
[MENU_ID_AWAY
])->active
= sess
->server
->is_away
;
1018 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_AWAY
], sess
->server
->connected
);
1019 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_JOIN
], sess
->server
->end_of_motd
);
1020 gtk_widget_set_sensitive (gui
->menu_item
[MENU_ID_DISCONNECT
],
1021 sess
->server
->connected
|| sess
->server
->recondelay_tag
);
1023 mg_set_topic_tip (sess
);
1025 plugin_emit_dummy_print (sess
, "Focus Tab");
1029 mg_bring_tofront_sess (session
*sess
) /* IRC tab or window */
1031 if (sess
->gui
->is_tab
)
1032 chan_focus (sess
->res
->tab
);
1034 gtk_window_present (GTK_WINDOW (sess
->gui
->window
));
1038 mg_bring_tofront (GtkWidget
*vbox
) /* non-IRC tab or window */
1042 ch
= g_object_get_data (G_OBJECT (vbox
), "ch");
1046 gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (vbox
)));
1050 mg_switch_page (int relative
, int num
)
1053 chanview_move_focus (mg_gui
->chanview
, relative
, num
);
1056 /* a toplevel IRC window was destroyed */
1059 mg_topdestroy_cb (GtkWidget
*win
, session
*sess
)
1061 /* printf("enter mg_topdestroy. sess %p was destroyed\n", sess);*/
1063 /* kill the text buffer */
1064 gtk_xtext_buffer_free (sess
->res
->buffer
);
1065 /* kill the user list */
1066 g_object_unref (G_OBJECT (sess
->res
->user_model
));
1068 session_free (sess
); /* tell xchat.c about it */
1071 /* cleanup an IRC tab */
1074 mg_ircdestroy (session
*sess
)
1078 /* kill the text buffer */
1079 gtk_xtext_buffer_free (sess
->res
->buffer
);
1080 /* kill the user list */
1081 g_object_unref (G_OBJECT (sess
->res
->user_model
));
1083 session_free (sess
); /* tell xchat.c about it */
1087 /* puts("-> mg_gui is already NULL");*/
1095 if (sess
->gui
->is_tab
)
1097 /* puts("-> some tabs still remain");*/
1103 /* puts("-> no tabs left, killing main tabwindow");*/
1104 gtk_widget_destroy (mg_gui
->window
);
1107 parent_window
= NULL
;
1111 mg_tab_close_cb (GtkWidget
*dialog
, gint arg1
, session
*sess
)
1113 GSList
*list
, *next
;
1115 gtk_widget_destroy (dialog
);
1116 if (arg1
== GTK_RESPONSE_OK
&& is_session (sess
))
1118 /* force it NOT to send individual PARTs */
1119 sess
->server
->sent_quit
= TRUE
;
1121 for (list
= sess_list
; list
;)
1124 if (((session
*)list
->data
)->server
== sess
->server
&&
1125 ((session
*)list
->data
) != sess
)
1126 fe_close_window ((session
*)list
->data
);
1130 /* just send one QUIT - better for BNCs */
1131 sess
->server
->sent_quit
= FALSE
;
1132 fe_close_window (sess
);
1137 mg_tab_close (session
*sess
)
1143 if (chan_remove (sess
->res
->tab
, FALSE
))
1144 mg_ircdestroy (sess
);
1147 for (i
= 0, list
= sess_list
; list
; list
= list
->next
)
1148 if (((session
*)list
->data
)->server
== sess
->server
)
1150 dialog
= gtk_message_dialog_new (GTK_WINDOW (parent_window
), 0,
1151 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK_CANCEL
,
1152 _("This server still has %d channels or dialogs associated with it. "
1153 "Close them all?"), i
);
1154 g_signal_connect (G_OBJECT (dialog
), "response",
1155 G_CALLBACK (mg_tab_close_cb
), sess
);
1156 if (prefs
.tab_layout
)
1158 gtk_window_set_position (GTK_WINDOW (dialog
), GTK_WIN_POS_MOUSE
);
1162 gtk_window_set_position (GTK_WINDOW (dialog
), GTK_WIN_POS_CENTER_ON_PARENT
);
1164 gtk_widget_show (dialog
);
1169 mg_menu_destroy (GtkWidget
*menu
, gpointer userdata
)
1171 gtk_widget_destroy (menu
);
1172 g_object_unref (menu
);
1176 mg_create_icon_item (char *label
, char *stock
, GtkWidget
*menu
,
1177 void *callback
, void *userdata
)
1181 item
= create_icon_menu (label
, stock
, TRUE
);
1182 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1183 g_signal_connect (G_OBJECT (item
), "activate", G_CALLBACK (callback
),
1185 gtk_widget_show (item
);
1189 mg_count_networks (void)
1194 for (list
= serv_list
; list
; list
= list
->next
)
1196 if (((server
*)list
->data
)->connected
)
1203 mg_count_dccs (void)
1213 if ((dcc
->type
== TYPE_SEND
|| dcc
->type
== TYPE_RECV
) &&
1214 dcc
->dccstat
== STAT_ACTIVE
)
1223 mg_open_quit_dialog (gboolean minimize_button
)
1225 static GtkWidget
*dialog
= NULL
;
1226 GtkWidget
*dialog_vbox1
;
1229 GtkWidget
*checkbutton1
;
1231 GtkWidget
*dialog_action_area1
;
1233 char *text
, *connecttext
;
1239 gtk_window_present (GTK_WINDOW (dialog
));
1243 dccs
= mg_count_dccs ();
1244 cons
= mg_count_networks ();
1245 if (dccs
+ cons
== 0 || !prefs
.gui_quit_dialog
)
1251 dialog
= gtk_dialog_new ();
1252 gtk_container_set_border_width (GTK_CONTAINER (dialog
), 6);
1253 gtk_window_set_title (GTK_WINDOW (dialog
), _("Quit XChat?"));
1254 gtk_window_set_transient_for (GTK_WINDOW (dialog
), GTK_WINDOW (parent_window
));
1255 gtk_window_set_resizable (GTK_WINDOW (dialog
), FALSE
);
1256 gtk_dialog_set_has_separator (GTK_DIALOG (dialog
), FALSE
);
1258 dialog_vbox1
= GTK_DIALOG (dialog
)->vbox
;
1259 gtk_widget_show (dialog_vbox1
);
1261 table1
= gtk_table_new (2, 2, FALSE
);
1262 gtk_widget_show (table1
);
1263 gtk_box_pack_start (GTK_BOX (dialog_vbox1
), table1
, TRUE
, TRUE
, 0);
1264 gtk_container_set_border_width (GTK_CONTAINER (table1
), 6);
1265 gtk_table_set_row_spacings (GTK_TABLE (table1
), 12);
1266 gtk_table_set_col_spacings (GTK_TABLE (table1
), 12);
1268 image
= gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_DIALOG
);
1269 gtk_widget_show (image
);
1270 gtk_table_attach (GTK_TABLE (table1
), image
, 0, 1, 0, 1,
1271 (GtkAttachOptions
) (GTK_FILL
),
1272 (GtkAttachOptions
) (GTK_FILL
), 0, 0);
1274 checkbutton1
= gtk_check_button_new_with_mnemonic (_("Don't ask next time."));
1275 gtk_widget_show (checkbutton1
);
1276 gtk_table_attach (GTK_TABLE (table1
), checkbutton1
, 0, 2, 1, 2,
1277 (GtkAttachOptions
) (GTK_EXPAND
| GTK_FILL
),
1278 (GtkAttachOptions
) (0), 0, 4);
1280 connecttext
= g_strdup_printf (_("You are connected to %i IRC networks."), cons
);
1281 text
= g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n%s",
1282 _("Are you sure you want to quit?"),
1283 cons
? connecttext
: "",
1284 dccs
? _("Some file transfers are still active.") : "");
1285 g_free (connecttext
);
1286 label
= gtk_label_new (text
);
1288 gtk_widget_show (label
);
1289 gtk_table_attach (GTK_TABLE (table1
), label
, 1, 2, 0, 1,
1290 (GtkAttachOptions
) (GTK_EXPAND
| GTK_SHRINK
| GTK_FILL
),
1291 (GtkAttachOptions
) (GTK_EXPAND
| GTK_SHRINK
), 0, 0);
1292 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
1293 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
1295 dialog_action_area1
= GTK_DIALOG (dialog
)->action_area
;
1296 gtk_widget_show (dialog_action_area1
);
1297 gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1
),
1300 if (minimize_button
)
1302 button
= gtk_button_new_with_mnemonic (_("_Minimize to Tray"));
1303 gtk_widget_show (button
);
1304 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
, 1);
1307 button
= gtk_button_new_from_stock ("gtk-cancel");
1308 gtk_widget_show (button
);
1309 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
,
1310 GTK_RESPONSE_CANCEL
);
1311 gtk_widget_grab_focus (button
);
1313 button
= gtk_button_new_from_stock ("gtk-quit");
1314 gtk_widget_show (button
);
1315 gtk_dialog_add_action_widget (GTK_DIALOG (dialog
), button
, 0);
1317 gtk_widget_show (dialog
);
1319 switch (gtk_dialog_run (GTK_DIALOG (dialog
)))
1322 if (GTK_TOGGLE_BUTTON (checkbutton1
)->active
)
1323 prefs
.gui_quit_dialog
= 0;
1326 case 1: /* minimize to tray */
1327 if (GTK_TOGGLE_BUTTON (checkbutton1
)->active
)
1329 prefs
.gui_tray_flags
|= 1;
1330 /*prefs.gui_quit_dialog = 0;*/
1332 /* force tray icon ON, if not already */
1333 if (!prefs
.gui_tray
)
1336 tray_apply_setup ();
1338 tray_toggle_visibility (TRUE
);
1342 gtk_widget_destroy (dialog
);
1347 mg_close_sess (session
*sess
)
1349 if (sess_list
->next
== NULL
)
1351 mg_open_quit_dialog (FALSE
);
1355 fe_close_window (sess
);
1359 mg_chan_remove (chan
*ch
)
1361 /* remove the tab from chanview */
1362 chan_remove (ch
, TRUE
);
1363 /* any tabs left? */
1364 if (chanview_get_size (mg_gui
->chanview
) < 1)
1366 /* if not, destroy the main tab window */
1367 gtk_widget_destroy (mg_gui
->window
);
1371 parent_window
= NULL
;
1377 /* destroy non-irc tab/window */
1380 mg_close_gen (chan
*ch
, GtkWidget
*box
)
1382 char *title
= g_object_get_data (G_OBJECT (box
), "title");
1387 ch
= g_object_get_data (G_OBJECT (box
), "ch");
1390 /* remove from notebook */
1391 gtk_widget_destroy (box
);
1392 /* remove the tab from chanview */
1393 mg_chan_remove (ch
);
1396 gtk_widget_destroy (gtk_widget_get_toplevel (box
));
1400 /* the "X" close button has been pressed (tab-view) */
1403 mg_xbutton_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer userdata
)
1405 if (tag
== TAG_IRC
) /* irc tab */
1406 mg_close_sess (userdata
);
1407 else /* non-irc utility tab */
1408 mg_close_gen (ch
, userdata
);
1412 mg_link_gentab (chan
*ch
, GtkWidget
*box
)
1419 num
= gtk_notebook_page_num (GTK_NOTEBOOK (mg_gui
->note_book
), box
);
1420 gtk_notebook_remove_page (GTK_NOTEBOOK (mg_gui
->note_book
), num
);
1421 mg_chan_remove (ch
);
1423 win
= gtkutil_window_new (g_object_get_data (G_OBJECT (box
), "title"), "",
1424 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (box
), "w")),
1425 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (box
), "h")),
1427 /* so it doesn't try to chan_remove (there's no tab anymore) */
1428 g_object_steal_data (G_OBJECT (box
), "ch");
1429 gtk_container_set_border_width (GTK_CONTAINER (box
), 0);
1430 gtk_container_add (GTK_CONTAINER (win
), box
);
1431 gtk_widget_show (win
);
1433 g_object_unref (box
);
1437 mg_detach_tab_cb (GtkWidget
*item
, chan
*ch
)
1439 if (chan_get_tag (ch
) == TAG_IRC
) /* IRC tab */
1441 /* userdata is session * */
1442 mg_link_irctab (chan_get_userdata (ch
), 1);
1446 /* userdata is GtkWidget * */
1447 mg_link_gentab (ch
, chan_get_userdata (ch
)); /* non-IRC tab */
1451 mg_destroy_tab_cb (GtkWidget
*item
, chan
*ch
)
1453 /* treat it just like the X button press */
1454 mg_xbutton_cb (mg_gui
->chanview
, ch
, chan_get_tag (ch
), chan_get_userdata (ch
));
1458 mg_color_insert (GtkWidget
*item
, gpointer userdata
)
1462 int num
= GPOINTER_TO_INT (userdata
);
1469 text
= "\002"; break;
1471 text
= "\037"; break;
1473 text
= "\035"; break;
1475 text
= "\017"; break;
1477 key_action_insert (current_sess
->gui
->input_box
, 0, text
, 0, 0);
1480 sprintf (buf
, "\003%02d", num
);
1481 key_action_insert (current_sess
->gui
->input_box
, 0, buf
, 0, 0);
1486 mg_markup_item (GtkWidget
*menu
, char *text
, int arg
)
1490 item
= gtk_menu_item_new_with_label ("");
1491 gtk_label_set_markup (GTK_LABEL (GTK_BIN (item
)->child
), text
);
1492 g_signal_connect (G_OBJECT (item
), "activate",
1493 G_CALLBACK (mg_color_insert
), GINT_TO_POINTER (arg
));
1494 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1495 gtk_widget_show (item
);
1499 mg_submenu (GtkWidget
*menu
, char *text
)
1501 GtkWidget
*submenu
, *item
;
1503 item
= gtk_menu_item_new_with_mnemonic (text
);
1504 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1505 gtk_widget_show (item
);
1507 submenu
= gtk_menu_new ();
1508 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item
), submenu
);
1509 gtk_widget_show (submenu
);
1515 mg_create_color_menu (GtkWidget
*menu
, session
*sess
)
1518 GtkWidget
*subsubmenu
;
1522 submenu
= mg_submenu (menu
, _("Insert Attribute or Color Code"));
1524 mg_markup_item (submenu
, _("<b>Bold</b>"), 100);
1525 mg_markup_item (submenu
, _("<u>Underline</u>"), 101);
1526 /*mg_markup_item (submenu, _("<i>Italic</i>"), 102);*/
1527 mg_markup_item (submenu
, _("Normal"), 103);
1529 subsubmenu
= mg_submenu (submenu
, _("Colors 0-7"));
1531 for (i
= 0; i
< 8; i
++)
1533 sprintf (buf
, "<tt><sup>%02d</sup> <span background=\"#%02x%02x%02x\">"
1535 i
, colors
[i
].red
>> 8, colors
[i
].green
>> 8, colors
[i
].blue
>> 8);
1536 mg_markup_item (subsubmenu
, buf
, i
);
1539 subsubmenu
= mg_submenu (submenu
, _("Colors 8-15"));
1541 for (i
= 8; i
< 16; i
++)
1543 sprintf (buf
, "<tt><sup>%02d</sup> <span background=\"#%02x%02x%02x\">"
1545 i
, colors
[i
].red
>> 8, colors
[i
].green
>> 8, colors
[i
].blue
>> 8);
1546 mg_markup_item (subsubmenu
, buf
, i
);
1551 mg_set_guint8 (GtkCheckMenuItem
*item
, guint8
*setting
)
1553 session
*sess
= current_sess
;
1554 guint8 logging
= sess
->text_logging
;
1560 /* has the logging setting changed? */
1561 if (logging
!= sess
->text_logging
)
1562 log_open_or_close (sess
);
1566 mg_perchan_menu_item (char *label
, GtkWidget
*menu
, guint8
*setting
, guint global
)
1568 guint8 initial_value
= *setting
;
1570 /* if it's using global value, use that as initial state */
1571 if (initial_value
== SET_DEFAULT
)
1572 initial_value
= global
;
1574 menu_toggle_item (label
, menu
, mg_set_guint8
, setting
, initial_value
);
1578 mg_create_perchannelmenu (session
*sess
, GtkWidget
*menu
)
1582 submenu
= menu_quick_sub (_("_Settings"), menu
, NULL
, XCMENU_MNEMONIC
, -1);
1584 mg_perchan_menu_item (_("_Log to Disk"), submenu
, &sess
->text_logging
, prefs
.logging
);
1585 mg_perchan_menu_item (_("_Reload Scrollback"), submenu
, &sess
->text_scrollback
, prefs
.text_replay
);
1586 if (sess
->type
== SESS_CHANNEL
)
1587 mg_perchan_menu_item (_("_Hide Join/Part Messages"), submenu
, &sess
->text_hidejoinpart
, prefs
.confmode
);
1591 mg_create_alertmenu (session
*sess
, GtkWidget
*menu
)
1595 submenu
= menu_quick_sub (_("_Extra Alerts"), menu
, NULL
, XCMENU_MNEMONIC
, -1);
1597 mg_perchan_menu_item (_("Beep on _Message"), submenu
, &sess
->alert_beep
, prefs
.input_beep_chans
);
1598 mg_perchan_menu_item (_("Blink Tray _Icon"), submenu
, &sess
->alert_tray
, prefs
.input_tray_chans
);
1599 mg_perchan_menu_item (_("Blink Task _Bar"), submenu
, &sess
->alert_taskbar
, prefs
.input_flash_chans
);
1603 mg_create_tabmenu (session
*sess
, GdkEventButton
*event
, chan
*ch
)
1605 GtkWidget
*menu
, *item
;
1608 menu
= gtk_menu_new ();
1612 char *name
= g_markup_escape_text (sess
->channel
[0] ? sess
->channel
: _("<none>"), -1);
1613 snprintf (buf
, sizeof (buf
), "<span foreground=\"#3344cc\"><b>%s</b></span>", name
);
1616 item
= gtk_menu_item_new_with_label ("");
1617 gtk_label_set_markup (GTK_LABEL (GTK_BIN (item
)->child
), buf
);
1618 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1619 gtk_widget_show (item
);
1622 menu_quick_item (0, 0, menu
, XCMENU_SHADED
, 0, 0);
1624 /* per-channel alerts */
1625 mg_create_alertmenu (sess
, menu
);
1627 /* per-channel settings */
1628 mg_create_perchannelmenu (sess
, menu
);
1631 menu_quick_item (0, 0, menu
, XCMENU_SHADED
, 0, 0);
1633 if (sess
->type
== SESS_CHANNEL
)
1634 menu_addfavoritemenu (sess
->server
, menu
, sess
->channel
);
1637 mg_create_icon_item (_("_Detach"), GTK_STOCK_REDO
, menu
,
1638 mg_detach_tab_cb
, ch
);
1639 mg_create_icon_item (_("_Close"), GTK_STOCK_CLOSE
, menu
,
1640 mg_destroy_tab_cb
, ch
);
1641 if (sess
&& tabmenu_list
)
1642 menu_create (menu
, tabmenu_list
, sess
->channel
, FALSE
);
1643 menu_add_plugin_items (menu
, "\x4$TAB", sess
->channel
);
1646 gtk_menu_set_screen (GTK_MENU (menu
), gdk_drawable_get_screen (event
->window
));
1647 g_object_ref (menu
);
1648 g_object_ref_sink (menu
);
1649 g_object_unref (menu
);
1650 g_signal_connect (G_OBJECT (menu
), "selection-done",
1651 G_CALLBACK (mg_menu_destroy
), NULL
);
1652 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
1656 mg_tab_contextmenu_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer ud
, GdkEventButton
*event
)
1658 /* shift-click to close a tab */
1659 if ((event
->state
& GDK_SHIFT_MASK
) && event
->type
== GDK_BUTTON_PRESS
)
1661 mg_xbutton_cb (cv
, ch
, tag
, ud
);
1665 if (event
->button
!= 3)
1669 mg_create_tabmenu (ud
, event
, ch
);
1671 mg_create_tabmenu (NULL
, event
, ch
);
1677 mg_dnd_drop_file (session
*sess
, char *target
, char *uri
)
1679 char *p
, *data
, *next
, *fname
;
1681 p
= data
= strdup (uri
);
1684 next
= strchr (p
, '\r');
1685 if (strncasecmp ("file:", p
, 5) == 0)
1689 fname
= g_filename_from_uri (p
, NULL
, NULL
);
1692 /* dcc_send() expects utf-8 */
1693 p
= xchat_filename_to_utf8 (fname
, -1, 0, 0, 0);
1696 dcc_send (sess
, target
, p
, prefs
.dcc_max_send_cps
, 0);
1713 mg_dialog_dnd_drop (GtkWidget
* widget
, GdkDragContext
* context
, gint x
,
1714 gint y
, GtkSelectionData
* selection_data
, guint info
,
1715 guint32 time
, gpointer ud
)
1717 if (current_sess
->type
== SESS_DIALOG
)
1718 /* sess->channel is really the nickname of dialogs */
1719 mg_dnd_drop_file (current_sess
, current_sess
->channel
, selection_data
->data
);
1722 /* add a tabbed channel */
1725 mg_add_chan (session
*sess
)
1728 char *name
= _("<none>");
1730 if (sess
->channel
[0])
1731 name
= sess
->channel
;
1745 sess
->res
->tab
= chanview_add (sess
->gui
->chanview
, name
, sess
->server
, sess
,
1746 sess
->type
== SESS_SERVER
? FALSE
: TRUE
,
1748 if (plain_list
== NULL
)
1749 mg_create_tab_colors ();
1751 chan_set_color (sess
->res
->tab
, plain_list
);
1753 if (sess
->res
->buffer
== NULL
)
1755 sess
->res
->buffer
= gtk_xtext_buffer_new (GTK_XTEXT (sess
->gui
->xtext
));
1756 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
1757 sess
->res
->user_model
= userlist_create_model ();
1762 mg_userlist_button (GtkWidget
* box
, char *label
, char *cmd
,
1763 int a
, int b
, int c
, int d
)
1765 GtkWidget
*wid
= gtk_button_new_with_label (label
);
1766 g_signal_connect (G_OBJECT (wid
), "clicked",
1767 G_CALLBACK (userlist_button_cb
), cmd
);
1768 gtk_table_attach_defaults (GTK_TABLE (box
), wid
, a
, b
, c
, d
);
1769 show_and_unfocus (wid
);
1773 mg_create_userlistbuttons (GtkWidget
*box
)
1776 GSList
*list
= button_list
;
1780 tab
= gtk_table_new (5, 2, FALSE
);
1781 gtk_box_pack_end (GTK_BOX (box
), tab
, FALSE
, FALSE
, 0);
1788 mg_userlist_button (tab
, pop
->name
, pop
->cmd
, a
, a
+ 1, b
, b
+ 1);
1803 mg_topic_cb (GtkWidget
*entry
, gpointer userdata
)
1805 session
*sess
= current_sess
;
1808 if (sess
->channel
[0] && sess
->server
->connected
&& sess
->type
== SESS_CHANNEL
)
1810 text
= GTK_ENTRY (entry
)->text
;
1813 sess
->server
->p_topic (sess
->server
, sess
->channel
, text
);
1815 gtk_entry_set_text (GTK_ENTRY (entry
), "");
1816 /* restore focus to the input widget, where the next input will most
1818 gtk_widget_grab_focus (sess
->gui
->input_box
);
1822 mg_tabwindow_kill_cb (GtkWidget
*win
, gpointer userdata
)
1824 GSList
*list
, *next
;
1827 /* puts("enter mg_tabwindow_kill_cb");*/
1828 xchat_is_quitting
= TRUE
;
1830 /* see if there's any non-tab windows left */
1836 if (!sess
->gui
->is_tab
)
1838 xchat_is_quitting
= FALSE
;
1839 /* puts("-> will not exit, some toplevel windows left");*/
1842 mg_ircdestroy (sess
);
1850 parent_window
= NULL
;
1854 mg_changui_destroy (session
*sess
)
1856 GtkWidget
*ret
= NULL
;
1858 if (sess
->gui
->is_tab
)
1860 /* avoid calling the "destroy" callback */
1861 g_signal_handlers_disconnect_by_func (G_OBJECT (sess
->gui
->window
),
1862 mg_tabwindow_kill_cb
, 0);
1863 /* remove the tab from the chanview */
1864 if (!mg_chan_remove (sess
->res
->tab
))
1865 /* if the window still exists, restore the signal handler */
1866 g_signal_connect (G_OBJECT (sess
->gui
->window
), "destroy",
1867 G_CALLBACK (mg_tabwindow_kill_cb
), 0);
1870 /* avoid calling the "destroy" callback */
1871 g_signal_handlers_disconnect_by_func (G_OBJECT (sess
->gui
->window
),
1872 mg_topdestroy_cb
, sess
);
1873 /*gtk_widget_destroy (sess->gui->window);*/
1874 /* don't destroy until the new one is created. Not sure why, but */
1875 /* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
1876 /* assertion `GDK_IS_COLORMAP (cmap)' failed */
1877 ret
= sess
->gui
->window
;
1885 mg_link_irctab (session
*sess
, int focus
)
1889 if (sess
->gui
->is_tab
)
1891 win
= mg_changui_destroy (sess
);
1892 mg_changui_new (sess
, sess
->res
, 0, focus
);
1894 xchat_is_quitting
= FALSE
;
1896 gtk_widget_destroy (win
);
1900 mg_unpopulate (sess
);
1901 win
= mg_changui_destroy (sess
);
1902 mg_changui_new (sess
, sess
->res
, 1, focus
);
1903 /* the buffer is now attached to a different widget */
1904 ((xtext_buffer
*)sess
->res
->buffer
)->xtext
= (GtkXText
*)sess
->gui
->xtext
;
1906 gtk_widget_destroy (win
);
1910 mg_detach (session
*sess
, int mode
)
1916 if (sess
->gui
->is_tab
)
1917 mg_link_irctab (sess
, 1);
1921 if (!sess
->gui
->is_tab
)
1922 mg_link_irctab (sess
, 1);
1926 mg_link_irctab (sess
, 1);
1931 check_is_number (char *t
)
1935 if (*t
< '0' || *t
> '9')
1943 mg_change_flag (GtkWidget
* wid
, session
*sess
, char flag
)
1945 server
*serv
= sess
->server
;
1950 if (serv
->connected
&& sess
->channel
[0])
1952 if (GTK_TOGGLE_BUTTON (wid
)->active
)
1956 serv
->p_mode (serv
, sess
->channel
, mode
);
1957 serv
->p_join_info (serv
, sess
->channel
);
1958 sess
->ignore_mode
= TRUE
;
1959 sess
->ignore_date
= TRUE
;
1964 flagl_hit (GtkWidget
* wid
, struct session
*sess
)
1967 const char *limit_str
;
1968 server
*serv
= sess
->server
;
1970 if (GTK_TOGGLE_BUTTON (wid
)->active
)
1972 if (serv
->connected
&& sess
->channel
[0])
1974 limit_str
= gtk_entry_get_text (GTK_ENTRY (sess
->gui
->limit_entry
));
1975 if (check_is_number ((char *)limit_str
) == FALSE
)
1977 fe_message (_("User limit must be a number!\n"), FE_MSG_ERROR
);
1978 gtk_entry_set_text (GTK_ENTRY (sess
->gui
->limit_entry
), "");
1979 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid
), FALSE
);
1982 snprintf (modes
, sizeof (modes
), "+l %d", atoi (limit_str
));
1983 serv
->p_mode (serv
, sess
->channel
, modes
);
1984 serv
->p_join_info (serv
, sess
->channel
);
1987 mg_change_flag (wid
, sess
, 'l');
1991 flagk_hit (GtkWidget
* wid
, struct session
*sess
)
1994 server
*serv
= sess
->server
;
1996 if (serv
->connected
&& sess
->channel
[0])
1998 snprintf (modes
, sizeof (modes
), "-k %s",
1999 gtk_entry_get_text (GTK_ENTRY (sess
->gui
->key_entry
)));
2001 if (GTK_TOGGLE_BUTTON (wid
)->active
)
2004 serv
->p_mode (serv
, sess
->channel
, modes
);
2009 mg_flagbutton_cb (GtkWidget
*but
, char *flag
)
2014 if (ignore_chanmode
)
2017 sess
= current_sess
;
2018 mode
= tolower ((unsigned char) flag
[0]);
2023 flagl_hit (but
, sess
);
2026 flagk_hit (but
, sess
);
2029 ignore_chanmode
= TRUE
;
2030 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess
->gui
->flag_b
), FALSE
);
2031 ignore_chanmode
= FALSE
;
2032 banlist_opengui (sess
);
2035 mg_change_flag (but
, sess
, mode
);
2040 mg_create_flagbutton (char *tip
, GtkWidget
*box
, char *face
)
2044 wid
= gtk_toggle_button_new_with_label (face
);
2045 gtk_widget_set_size_request (wid
, 18, 0);
2047 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2048 g_signal_connect (G_OBJECT (wid
), "toggled",
2049 G_CALLBACK (mg_flagbutton_cb
), face
);
2050 show_and_unfocus (wid
);
2056 mg_key_entry_cb (GtkWidget
* igad
, gpointer userdata
)
2059 session
*sess
= current_sess
;
2060 server
*serv
= sess
->server
;
2062 if (serv
->connected
&& sess
->channel
[0])
2064 snprintf (modes
, sizeof (modes
), "+k %s",
2065 gtk_entry_get_text (GTK_ENTRY (igad
)));
2066 serv
->p_mode (serv
, sess
->channel
, modes
);
2067 serv
->p_join_info (serv
, sess
->channel
);
2072 mg_limit_entry_cb (GtkWidget
* igad
, gpointer userdata
)
2075 session
*sess
= current_sess
;
2076 server
*serv
= sess
->server
;
2078 if (serv
->connected
&& sess
->channel
[0])
2080 if (check_is_number ((char *)gtk_entry_get_text (GTK_ENTRY (igad
))) == FALSE
)
2082 gtk_entry_set_text (GTK_ENTRY (igad
), "");
2083 fe_message (_("User limit must be a number!\n"), FE_MSG_ERROR
);
2084 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess
->gui
->flag_l
), FALSE
);
2087 snprintf (modes
, sizeof(modes
), "+l %d",
2088 atoi (gtk_entry_get_text (GTK_ENTRY (igad
))));
2089 serv
->p_mode (serv
, sess
->channel
, modes
);
2090 serv
->p_join_info (serv
, sess
->channel
);
2095 mg_apply_entry_style (GtkWidget
*entry
)
2097 gtk_widget_modify_base (entry
, GTK_STATE_NORMAL
, &colors
[COL_BG
]);
2098 gtk_widget_modify_text (entry
, GTK_STATE_NORMAL
, &colors
[COL_FG
]);
2099 gtk_widget_modify_font (entry
, input_style
->font_desc
);
2103 mg_create_chanmodebuttons (session_gui
*gui
, GtkWidget
*box
)
2105 gui
->flag_t
= mg_create_flagbutton (_("Topic Protection"), box
, "T");
2106 gui
->flag_n
= mg_create_flagbutton (_("No outside messages"), box
, "N");
2107 gui
->flag_s
= mg_create_flagbutton (_("Secret"), box
, "S");
2108 gui
->flag_i
= mg_create_flagbutton (_("Invite Only"), box
, "I");
2109 gui
->flag_p
= mg_create_flagbutton (_("Private"), box
, "P");
2110 gui
->flag_m
= mg_create_flagbutton (_("Moderated"), box
, "M");
2111 gui
->flag_b
= mg_create_flagbutton (_("Ban List"), box
, "B");
2113 gui
->flag_k
= mg_create_flagbutton (_("Keyword"), box
, "K");
2114 gui
->key_entry
= gtk_entry_new ();
2115 gtk_widget_set_name (gui
->key_entry
, "xchat-inputbox");
2116 gtk_entry_set_max_length (GTK_ENTRY (gui
->key_entry
), 16);
2117 gtk_widget_set_size_request (gui
->key_entry
, 30, -1);
2118 gtk_box_pack_start (GTK_BOX (box
), gui
->key_entry
, 0, 0, 0);
2119 g_signal_connect (G_OBJECT (gui
->key_entry
), "activate",
2120 G_CALLBACK (mg_key_entry_cb
), NULL
);
2122 if (prefs
.style_inputbox
)
2123 mg_apply_entry_style (gui
->key_entry
);
2125 gui
->flag_l
= mg_create_flagbutton (_("User Limit"), box
, "L");
2126 gui
->limit_entry
= gtk_entry_new ();
2127 gtk_widget_set_name (gui
->limit_entry
, "xchat-inputbox");
2128 gtk_entry_set_max_length (GTK_ENTRY (gui
->limit_entry
), 10);
2129 gtk_widget_set_size_request (gui
->limit_entry
, 30, -1);
2130 gtk_box_pack_start (GTK_BOX (box
), gui
->limit_entry
, 0, 0, 0);
2131 g_signal_connect (G_OBJECT (gui
->limit_entry
), "activate",
2132 G_CALLBACK (mg_limit_entry_cb
), NULL
);
2134 if (prefs
.style_inputbox
)
2135 mg_apply_entry_style (gui
->limit_entry
);
2139 mg_create_link_buttons (GtkWidget *box, gpointer userdata)
2141 gtkutil_button (box, GTK_STOCK_CLOSE, _("Close this tab/window"),
2142 mg_x_click_cb, userdata, 0);
2145 gtkutil_button (box, GTK_STOCK_REDO, _("Attach/Detach this tab"),
2146 mg_link_cb, userdata, 0);
2150 mg_dialog_button_cb (GtkWidget
*wid
, char *cmd
)
2152 /* the longest cmd is 12, and the longest nickname is 64 */
2160 topic
= (char *)(GTK_ENTRY (current_sess
->gui
->topic_entry
)->text
);
2161 topic
= strrchr (topic
, '@');
2165 auto_insert (buf
, sizeof (buf
), cmd
, 0, 0, "", "", "",
2166 server_get_network (current_sess
->server
, TRUE
), host
, "",
2167 current_sess
->channel
);
2169 handle_command (current_sess
, buf
, TRUE
);
2171 /* dirty trick to avoid auto-selection */
2172 SPELL_ENTRY_SET_EDITABLE (current_sess
->gui
->input_box
, FALSE
);
2173 gtk_widget_grab_focus (current_sess
->gui
->input_box
);
2174 SPELL_ENTRY_SET_EDITABLE (current_sess
->gui
->input_box
, TRUE
);
2178 mg_dialog_button (GtkWidget
*box
, char *name
, char *cmd
)
2182 wid
= gtk_button_new_with_label (name
);
2183 gtk_box_pack_start (GTK_BOX (box
), wid
, FALSE
, FALSE
, 0);
2184 g_signal_connect (G_OBJECT (wid
), "clicked",
2185 G_CALLBACK (mg_dialog_button_cb
), cmd
);
2186 gtk_widget_set_size_request (wid
, -1, 0);
2190 mg_create_dialogbuttons (GtkWidget
*box
)
2193 GSList
*list
= dlgbutton_list
;
2199 mg_dialog_button (box
, pop
->name
, pop
->cmd
);
2205 mg_create_topicbar (session
*sess
, GtkWidget
*box
)
2207 GtkWidget
*hbox
, *topic
, *bbox
;
2208 session_gui
*gui
= sess
->gui
;
2210 gui
->topic_bar
= hbox
= gtk_hbox_new (FALSE
, 0);
2211 gtk_box_pack_start (GTK_BOX (box
), hbox
, 0, 0, 0);
2214 sess
->res
->tab
= NULL
;
2216 gui
->topic_entry
= topic
= gtk_entry_new ();
2217 gtk_widget_set_name (topic
, "xchat-inputbox");
2218 gtk_container_add (GTK_CONTAINER (hbox
), topic
);
2219 g_signal_connect (G_OBJECT (topic
), "activate",
2220 G_CALLBACK (mg_topic_cb
), 0);
2222 if (prefs
.style_inputbox
)
2223 mg_apply_entry_style (topic
);
2225 gui
->topicbutton_box
= bbox
= gtk_hbox_new (FALSE
, 0);
2226 gtk_box_pack_start (GTK_BOX (hbox
), bbox
, 0, 0, 0);
2227 mg_create_chanmodebuttons (gui
, bbox
);
2229 gui
->dialogbutton_box
= bbox
= gtk_hbox_new (FALSE
, 0);
2230 gtk_box_pack_start (GTK_BOX (hbox
), bbox
, 0, 0, 0);
2231 mg_create_dialogbuttons (bbox
);
2233 if (!prefs
.paned_userlist
)
2234 gtkutil_button (hbox
, GTK_STOCK_GOTO_LAST
, _("Show/Hide userlist"),
2235 mg_userlist_toggle_cb
, 0, 0);
2238 /* check if a word is clickable */
2241 mg_word_check (GtkWidget
* xtext
, char *word
, int len
)
2243 session
*sess
= current_sess
;
2246 ret
= url_check_word (word
, len
); /* common/url.c */
2249 if (( (word
[0]=='@' || word
[0]=='+' || word
[0]=='%') && userlist_find (sess
, word
+1)) || userlist_find (sess
, word
))
2252 if (sess
->type
== SESS_DIALOG
)
2259 /* mouse click inside text area */
2262 mg_word_clicked (GtkWidget
*xtext
, char *word
, GdkEventButton
*even
)
2264 session
*sess
= current_sess
;
2266 if (even
->button
== 1) /* left button */
2274 if ((even
->state
& 13) == prefs
.gui_url_mod
)
2276 switch (mg_word_check (xtext
, word
, strlen (word
)))
2286 if (even
->button
== 2)
2288 if (sess
->type
== SESS_DIALOG
)
2289 menu_middlemenu (sess
, even
);
2290 else if (even
->type
== GDK_2BUTTON_PRESS
)
2291 userlist_select (sess
, word
);
2295 switch (mg_word_check (xtext
, word
, strlen (word
)))
2298 menu_middlemenu (sess
, even
);
2302 menu_urlmenu (even
, word
);
2305 menu_nickmenu (sess
, even
, (word
[0]=='@' || word
[0]=='+' || word
[0]=='%') ?
2306 word
+1 : word
, FALSE
);
2309 if (*word
== '@' || *word
== '+' || *word
=='^' || *word
=='%' || *word
=='*')
2311 menu_chanmenu (sess
, even
, word
);
2315 char *newword
= malloc (strlen (word
) + 10);
2318 sprintf (newword
, "mailto:%s", word
);
2319 menu_urlmenu (even
, newword
);
2324 menu_nickmenu (sess
, even
, sess
->channel
, FALSE
);
2330 mg_update_xtext (GtkWidget
*wid
)
2332 GtkXText
*xtext
= GTK_XTEXT (wid
);
2334 gtk_xtext_set_palette (xtext
, colors
);
2335 gtk_xtext_set_max_lines (xtext
, prefs
.max_lines
);
2336 gtk_xtext_set_tint (xtext
, prefs
.tint_red
, prefs
.tint_green
, prefs
.tint_blue
);
2337 gtk_xtext_set_background (xtext
, channelwin_pix
, prefs
.transparent
);
2338 gtk_xtext_set_wordwrap (xtext
, prefs
.wordwrap
);
2339 gtk_xtext_set_show_marker (xtext
, prefs
.show_marker
);
2340 gtk_xtext_set_show_separator (xtext
, prefs
.indent_nicks
? prefs
.show_separator
: 0);
2341 gtk_xtext_set_indent (xtext
, prefs
.indent_nicks
);
2342 if (!gtk_xtext_set_font (xtext
, prefs
.font_normal
))
2344 fe_message ("Failed to open any font. I'm out of here!", FE_MSG_WAIT
| FE_MSG_ERROR
);
2348 gtk_xtext_refresh (xtext
, FALSE
);
2351 /* handle errors reported by xtext */
2354 mg_xtext_error (int type
)
2359 fe_message (_("Unable to set transparent background!\n\n"
2360 "You may be using a non-compliant window\n"
2361 "manager that is not currently supported.\n"), FE_MSG_WARN
);
2362 prefs
.transparent
= 0;
2363 /* no others exist yet */
2368 mg_create_textarea (session
*sess
, GtkWidget
*box
)
2370 GtkWidget
*inbox
, *vbox
, *frame
;
2372 session_gui
*gui
= sess
->gui
;
2373 static const GtkTargetEntry dnd_targets
[] =
2375 {"text/uri-list", 0, 1}
2377 static const GtkTargetEntry dnd_dest_targets
[] =
2379 {"XCHAT_CHANVIEW", GTK_TARGET_SAME_APP
, 75 },
2380 {"XCHAT_USERLIST", GTK_TARGET_SAME_APP
, 75 }
2383 vbox
= gtk_vbox_new (FALSE
, 0);
2384 gtk_container_add (GTK_CONTAINER (box
), vbox
);
2386 inbox
= gtk_hbox_new (FALSE
, SCROLLBAR_SPACING
);
2387 gtk_container_add (GTK_CONTAINER (vbox
), inbox
);
2389 frame
= gtk_frame_new (NULL
);
2390 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_IN
);
2391 gtk_container_add (GTK_CONTAINER (inbox
), frame
);
2393 gui
->xtext
= gtk_xtext_new (colors
, TRUE
);
2394 xtext
= GTK_XTEXT (gui
->xtext
);
2395 gtk_xtext_set_max_indent (xtext
, prefs
.max_auto_indent
);
2396 gtk_xtext_set_thin_separator (xtext
, prefs
.thin_separator
);
2397 gtk_xtext_set_error_function (xtext
, mg_xtext_error
);
2398 gtk_xtext_set_urlcheck_function (xtext
, mg_word_check
);
2399 gtk_xtext_set_max_lines (xtext
, prefs
.max_lines
);
2400 gtk_container_add (GTK_CONTAINER (frame
), GTK_WIDGET (xtext
));
2401 mg_update_xtext (GTK_WIDGET (xtext
));
2403 g_signal_connect (G_OBJECT (xtext
), "word_click",
2404 G_CALLBACK (mg_word_clicked
), NULL
);
2406 gui
->vscrollbar
= gtk_vscrollbar_new (GTK_XTEXT (xtext
)->adj
);
2407 gtk_box_pack_start (GTK_BOX (inbox
), gui
->vscrollbar
, FALSE
, TRUE
, 0);
2408 gtk_drag_dest_set (gui
->vscrollbar
, 5, dnd_dest_targets
, 2,
2409 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
);
2410 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_begin",
2411 G_CALLBACK (mg_drag_begin_cb
), NULL
);
2412 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_drop",
2413 G_CALLBACK (mg_drag_drop_cb
), NULL
);
2414 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_motion",
2415 G_CALLBACK (mg_drag_motion_cb
), gui
->vscrollbar
);
2416 g_signal_connect (G_OBJECT (gui
->vscrollbar
), "drag_end",
2417 G_CALLBACK (mg_drag_end_cb
), NULL
);
2419 gtk_drag_dest_set (gui
->xtext
, GTK_DEST_DEFAULT_ALL
, dnd_targets
, 1,
2420 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
);
2421 g_signal_connect (G_OBJECT (gui
->xtext
), "drag_data_received",
2422 G_CALLBACK (mg_dialog_dnd_drop
), NULL
);
2426 mg_create_infoframe (GtkWidget
*box
)
2428 GtkWidget
*frame
, *label
, *hbox
;
2430 frame
= gtk_frame_new (0);
2431 gtk_frame_set_shadow_type ((GtkFrame
*)frame
, GTK_SHADOW_OUT
);
2432 gtk_container_add (GTK_CONTAINER (box
), frame
);
2434 hbox
= gtk_hbox_new (0, 0);
2435 gtk_container_add (GTK_CONTAINER (frame
), hbox
);
2437 label
= gtk_label_new (NULL
);
2438 gtk_container_add (GTK_CONTAINER (hbox
), label
);
2444 mg_create_meters (session_gui
*gui
, GtkWidget
*parent_box
)
2446 GtkWidget
*infbox
, *wid
, *box
;
2448 gui
->meter_box
= infbox
= box
= gtk_vbox_new (0, 1);
2449 gtk_box_pack_start (GTK_BOX (parent_box
), box
, 0, 0, 0);
2451 if ((prefs
.lagometer
& 2) || (prefs
.throttlemeter
& 2))
2453 infbox
= gtk_hbox_new (0, 0);
2454 gtk_box_pack_start (GTK_BOX (box
), infbox
, 0, 0, 0);
2457 if (prefs
.lagometer
& 1)
2459 gui
->lagometer
= wid
= gtk_progress_bar_new ();
2460 gtk_widget_set_size_request (wid
, 1, 8);
2462 wid
= gtk_event_box_new ();
2463 gtk_container_add (GTK_CONTAINER (wid
), gui
->lagometer
);
2464 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2466 if (prefs
.lagometer
& 2)
2468 gui
->laginfo
= wid
= mg_create_infoframe (infbox
);
2469 gtk_label_set_text ((GtkLabel
*) wid
, "Lag");
2472 if (prefs
.throttlemeter
& 1)
2474 gui
->throttlemeter
= wid
= gtk_progress_bar_new ();
2475 gtk_widget_set_size_request (wid
, 1, 8);
2477 wid
= gtk_event_box_new ();
2478 gtk_container_add (GTK_CONTAINER (wid
), gui
->throttlemeter
);
2479 gtk_box_pack_start (GTK_BOX (box
), wid
, 0, 0, 0);
2481 if (prefs
.throttlemeter
& 2)
2483 gui
->throttleinfo
= wid
= mg_create_infoframe (infbox
);
2484 gtk_label_set_text ((GtkLabel
*) wid
, "Throttle");
2489 mg_update_meters (session_gui
*gui
)
2491 gtk_widget_destroy (gui
->meter_box
);
2492 gui
->lagometer
= NULL
;
2493 gui
->laginfo
= NULL
;
2494 gui
->throttlemeter
= NULL
;
2495 gui
->throttleinfo
= NULL
;
2497 mg_create_meters (gui
, gui
->button_box_parent
);
2498 gtk_widget_show_all (gui
->meter_box
);
2502 mg_create_userlist (session_gui
*gui
, GtkWidget
*box
)
2504 GtkWidget
*frame
, *ulist
, *vbox
;
2506 vbox
= gtk_vbox_new (0, 1);
2507 gtk_container_add (GTK_CONTAINER (box
), vbox
);
2509 frame
= gtk_frame_new (NULL
);
2510 if (!(prefs
.gui_tweaks
& 1))
2511 gtk_box_pack_start (GTK_BOX (vbox
), frame
, 0, 0, GUI_SPACING
);
2513 gui
->namelistinfo
= gtk_label_new (NULL
);
2514 gtk_container_add (GTK_CONTAINER (frame
), gui
->namelistinfo
);
2516 gui
->user_tree
= ulist
= userlist_create (vbox
);
2518 if (prefs
.style_namelistgad
)
2520 gtk_widget_set_style (ulist
, input_style
);
2521 gtk_widget_modify_base (ulist
, GTK_STATE_NORMAL
, &colors
[COL_BG
]);
2524 mg_create_meters (gui
, vbox
);
2526 gui
->button_box_parent
= vbox
;
2527 gui
->button_box
= mg_create_userlistbuttons (vbox
);
2531 mg_leftpane_cb (GtkPaned
*pane
, GParamSpec
*param
, session_gui
*gui
)
2533 prefs
.gui_pane_left_size
= gtk_paned_get_position (pane
);
2537 mg_rightpane_cb (GtkPaned
*pane
, GParamSpec
*param
, session_gui
*gui
)
2541 /* if (pane->child1 == NULL || (!GTK_WIDGET_VISIBLE (pane->child1)))
2543 if (pane->child2 == NULL || (!GTK_WIDGET_VISIBLE (pane->child2)))
2546 gtk_widget_style_get (GTK_WIDGET (pane
), "handle-size", &handle_size
, NULL
);
2547 /* record the position from the RIGHT side */
2548 prefs
.gui_pane_right_size
= GTK_WIDGET (pane
)->allocation
.width
- gtk_paned_get_position (pane
) - handle_size
;
2552 mg_add_pane_signals (session_gui
*gui
)
2554 g_signal_connect (G_OBJECT (gui
->hpane_right
), "notify::position",
2555 G_CALLBACK (mg_rightpane_cb
), gui
);
2556 g_signal_connect (G_OBJECT (gui
->hpane_left
), "notify::position",
2557 G_CALLBACK (mg_leftpane_cb
), gui
);
2562 mg_create_center (session
*sess
, session_gui
*gui
, GtkWidget
*box
)
2564 GtkWidget
*vbox
, *hbox
, *book
;
2566 /* sep between top and bottom of left side */
2567 gui
->vpane_left
= gtk_vpaned_new ();
2569 /* sep between top and bottom of right side */
2570 gui
->vpane_right
= gtk_vpaned_new ();
2572 /* sep between left and xtext */
2573 gui
->hpane_left
= gtk_hpaned_new ();
2574 gtk_paned_set_position (GTK_PANED (gui
->hpane_left
), prefs
.gui_pane_left_size
);
2576 /* sep between xtext and right side */
2577 gui
->hpane_right
= gtk_hpaned_new ();
2579 if (prefs
.gui_tweaks
& 4)
2581 gtk_paned_pack2 (GTK_PANED (gui
->hpane_left
), gui
->vpane_left
, FALSE
, TRUE
);
2582 gtk_paned_pack1 (GTK_PANED (gui
->hpane_left
), gui
->hpane_right
, TRUE
, TRUE
);
2586 gtk_paned_pack1 (GTK_PANED (gui
->hpane_left
), gui
->vpane_left
, FALSE
, TRUE
);
2587 gtk_paned_pack2 (GTK_PANED (gui
->hpane_left
), gui
->hpane_right
, TRUE
, TRUE
);
2589 gtk_paned_pack2 (GTK_PANED (gui
->hpane_right
), gui
->vpane_right
, FALSE
, TRUE
);
2591 gtk_container_add (GTK_CONTAINER (box
), gui
->hpane_left
);
2593 gui
->note_book
= book
= gtk_notebook_new ();
2594 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book
), FALSE
);
2595 gtk_notebook_set_show_border (GTK_NOTEBOOK (book
), FALSE
);
2596 gtk_paned_pack1 (GTK_PANED (gui
->hpane_right
), book
, TRUE
, TRUE
);
2598 hbox
= gtk_hbox_new (FALSE
, 0);
2599 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), hbox
, FALSE
, TRUE
);
2600 mg_create_userlist (gui
, hbox
);
2602 gui
->user_box
= hbox
;
2604 vbox
= gtk_vbox_new (FALSE
, 3);
2605 gtk_notebook_append_page (GTK_NOTEBOOK (book
), vbox
, NULL
);
2606 mg_create_topicbar (sess
, vbox
);
2607 mg_create_textarea (sess
, vbox
);
2608 mg_create_entry (sess
, vbox
);
2610 g_idle_add ((GSourceFunc
)mg_add_pane_signals
, gui
);
2614 mg_change_nick (int cancel
, char *text
, gpointer userdata
)
2620 snprintf (buf
, sizeof (buf
), "nick %s", text
);
2621 handle_command (current_sess
, buf
, FALSE
);
2626 mg_nickclick_cb (GtkWidget
*button
, gpointer userdata
)
2628 fe_get_str (_("Enter new nickname:"), current_sess
->server
->nick
,
2629 mg_change_nick
, NULL
);
2632 /* make sure chanview and userlist positions are sane */
2635 mg_sanitize_positions (int *cv
, int *ul
)
2637 if (prefs
.tab_layout
== 2)
2639 /* treeview can't be on TOP or BOTTOM */
2640 if (*cv
== POS_TOP
|| *cv
== POS_BOTTOM
)
2644 /* userlist can't be on TOP or BOTTOM */
2645 if (*ul
== POS_TOP
|| *ul
== POS_BOTTOM
)
2648 /* can't have both in the same place */
2652 if (*ul
== POS_TOPRIGHT
)
2653 *cv
= POS_BOTTOMRIGHT
;
2658 mg_place_userlist_and_chanview_real (session_gui
*gui
, GtkWidget
*userlist
, GtkWidget
*chanview
)
2660 int unref_userlist
= FALSE
;
2661 int unref_chanview
= FALSE
;
2663 /* first, remove userlist/treeview from their containers */
2664 if (userlist
&& userlist
->parent
)
2666 g_object_ref (userlist
);
2667 gtk_container_remove (GTK_CONTAINER (userlist
->parent
), userlist
);
2668 unref_userlist
= TRUE
;
2671 if (chanview
&& chanview
->parent
)
2673 g_object_ref (chanview
);
2674 gtk_container_remove (GTK_CONTAINER (chanview
->parent
), chanview
);
2675 unref_chanview
= TRUE
;
2680 /* incase the previous pos was POS_HIDDEN */
2681 gtk_widget_show (chanview
);
2683 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 1, 0);
2684 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 2, 2);
2686 /* then place them back in their new positions */
2687 switch (prefs
.tab_pos
)
2690 gtk_paned_pack1 (GTK_PANED (gui
->vpane_left
), chanview
, FALSE
, TRUE
);
2692 case POS_BOTTOMLEFT
:
2693 gtk_paned_pack2 (GTK_PANED (gui
->vpane_left
), chanview
, FALSE
, TRUE
);
2696 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), chanview
, FALSE
, TRUE
);
2698 case POS_BOTTOMRIGHT
:
2699 gtk_paned_pack2 (GTK_PANED (gui
->vpane_right
), chanview
, FALSE
, TRUE
);
2702 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 1, GUI_SPACING
-1);
2703 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2704 1, 2, 1, 2, GTK_FILL
, GTK_FILL
, 0, 0);
2707 gtk_widget_hide (chanview
);
2708 /* always attach it to something to avoid ref_count=0 */
2709 if (prefs
.gui_ulist_pos
== POS_TOP
)
2710 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2711 1, 2, 3, 4, GTK_FILL
, GTK_FILL
, 0, 0);
2714 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2715 1, 2, 1, 2, GTK_FILL
, GTK_FILL
, 0, 0);
2717 default:/* POS_BOTTOM */
2718 gtk_table_set_row_spacing (GTK_TABLE (gui
->main_table
), 2, 3);
2719 gtk_table_attach (GTK_TABLE (gui
->main_table
), chanview
,
2720 1, 2, 3, 4, GTK_FILL
, GTK_FILL
, 0, 0);
2726 switch (prefs
.gui_ulist_pos
)
2729 gtk_paned_pack1 (GTK_PANED (gui
->vpane_left
), userlist
, FALSE
, TRUE
);
2731 case POS_BOTTOMLEFT
:
2732 gtk_paned_pack2 (GTK_PANED (gui
->vpane_left
), userlist
, FALSE
, TRUE
);
2734 case POS_BOTTOMRIGHT
:
2735 gtk_paned_pack2 (GTK_PANED (gui
->vpane_right
), userlist
, FALSE
, TRUE
);
2738 break;*/ /* Hide using the VIEW menu instead */
2739 default:/* POS_TOPRIGHT */
2740 gtk_paned_pack1 (GTK_PANED (gui
->vpane_right
), userlist
, FALSE
, TRUE
);
2745 g_object_unref (chanview
);
2747 g_object_unref (userlist
);
2749 mg_hide_empty_boxes (gui
);
2753 mg_place_userlist_and_chanview (session_gui
*gui
)
2755 GtkOrientation orientation
;
2756 GtkWidget
*chanviewbox
= NULL
;
2759 mg_sanitize_positions (&prefs
.tab_pos
, &prefs
.gui_ulist_pos
);
2763 pos
= prefs
.tab_pos
;
2765 orientation
= chanview_get_orientation (gui
->chanview
);
2766 if ((pos
== POS_BOTTOM
|| pos
== POS_TOP
) && orientation
== GTK_ORIENTATION_VERTICAL
)
2767 chanview_set_orientation (gui
->chanview
, FALSE
);
2768 else if ((pos
== POS_TOPLEFT
|| pos
== POS_BOTTOMLEFT
|| pos
== POS_TOPRIGHT
|| pos
== POS_BOTTOMRIGHT
) && orientation
== GTK_ORIENTATION_HORIZONTAL
)
2769 chanview_set_orientation (gui
->chanview
, TRUE
);
2770 chanviewbox
= chanview_get_box (gui
->chanview
);
2773 mg_place_userlist_and_chanview_real (gui
, gui
->user_box
, chanviewbox
);
2777 mg_change_layout (int type
)
2781 /* put tabs at the bottom */
2782 if (type
== 0 && prefs
.tab_pos
!= POS_BOTTOM
&& prefs
.tab_pos
!= POS_TOP
)
2783 prefs
.tab_pos
= POS_BOTTOM
;
2785 mg_place_userlist_and_chanview (mg_gui
);
2786 chanview_set_impl (mg_gui
->chanview
, type
);
2791 mg_inputbox_rightclick (GtkEntry
*entry
, GtkWidget
*menu
)
2793 mg_create_color_menu (menu
, NULL
);
2797 mg_create_entry (session
*sess
, GtkWidget
*box
)
2799 GtkWidget
*sw
, *hbox
, *but
, *entry
;
2800 session_gui
*gui
= sess
->gui
;
2802 hbox
= gtk_hbox_new (FALSE
, 0);
2803 gtk_box_pack_start (GTK_BOX (box
), hbox
, 0, 0, 0);
2805 gui
->nick_box
= gtk_hbox_new (FALSE
, 0);
2806 gtk_box_pack_start (GTK_BOX (hbox
), gui
->nick_box
, 0, 0, 0);
2808 gui
->nick_label
= but
= gtk_button_new_with_label (sess
->server
->nick
);
2809 gtk_button_set_relief (GTK_BUTTON (but
), GTK_RELIEF_NONE
);
2810 GTK_WIDGET_UNSET_FLAGS (but
, GTK_CAN_FOCUS
);
2811 gtk_box_pack_end (GTK_BOX (gui
->nick_box
), but
, 0, 0, 0);
2812 g_signal_connect (G_OBJECT (but
), "clicked",
2813 G_CALLBACK (mg_nickclick_cb
), NULL
);
2816 gui
->input_box
= entry
= gtk_text_view_new ();
2817 gtk_widget_set_size_request (entry
, 0, 1);
2818 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (entry
), GTK_WRAP_NONE
);
2819 gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (entry
), FALSE
);
2820 if (prefs
.gui_input_spell
)
2821 gtkspell_new_attach (GTK_TEXT_VIEW (entry
), NULL
, NULL
);
2823 sw
= gtk_scrolled_window_new (NULL
, NULL
);
2824 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw
),
2826 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
2829 gtk_container_add (GTK_CONTAINER (sw
), entry
);
2830 gtk_container_add (GTK_CONTAINER (hbox
), sw
);
2833 gui
->input_box
= entry
= sexy_spell_entry_new ();
2834 sexy_spell_entry_set_checked ((SexySpellEntry
*)entry
, prefs
.gui_input_spell
);
2836 gui
->input_box
= entry
= gtk_entry_new ();
2838 gtk_entry_set_max_length (GTK_ENTRY (gui
->input_box
), 2048);
2839 g_signal_connect (G_OBJECT (entry
), "activate",
2840 G_CALLBACK (mg_inputbox_cb
), gui
);
2841 gtk_container_add (GTK_CONTAINER (hbox
), entry
);
2844 gtk_widget_set_name (entry
, "xchat-inputbox");
2845 g_signal_connect (G_OBJECT (entry
), "key_press_event",
2846 G_CALLBACK (key_handle_key_press
), NULL
);
2847 g_signal_connect (G_OBJECT (entry
), "focus_in_event",
2848 G_CALLBACK (mg_inputbox_focus
), gui
);
2849 g_signal_connect (G_OBJECT (entry
), "populate_popup",
2850 G_CALLBACK (mg_inputbox_rightclick
), NULL
);
2851 gtk_widget_grab_focus (entry
);
2853 if (prefs
.style_inputbox
)
2854 mg_apply_entry_style (entry
);
2858 mg_switch_tab_cb (chanview
*cv
, chan
*ch
, int tag
, gpointer ud
)
2868 if (active_tab
!= old
)
2870 if (old
&& current_tab
)
2871 mg_unpopulate (current_tab
);
2874 } else if (old
!= active_tab
)
2876 /* userdata for non-irc tabs is actually the GtkBox */
2877 mg_show_generic_tab (ud
);
2878 if (!mg_is_userlist_and_tree_combined ())
2879 mg_userlist_showhide (current_sess
, FALSE
); /* hide */
2883 /* compare two tabs (for tab sorting function) */
2886 mg_tabs_compare (session
*a
, session
*b
)
2888 /* server tabs always go first */
2889 if (a
->type
== SESS_SERVER
)
2893 if (a
->type
== SESS_CHANNEL
&& b
->type
!= SESS_CHANNEL
)
2895 if (a
->type
!= SESS_CHANNEL
&& b
->type
== SESS_CHANNEL
)
2898 return strcasecmp (a
->channel
, b
->channel
);
2902 mg_create_tabs (session_gui
*gui
)
2904 gboolean use_icons
= FALSE
;
2906 /* if any one of these PNGs exist, the chanview will create
2907 * the extra column for icons. */
2908 if (pix_channel
|| pix_dialog
|| pix_server
|| pix_util
)
2911 gui
->chanview
= chanview_new (prefs
.tab_layout
, prefs
.truncchans
,
2912 prefs
.tab_sort
, use_icons
,
2913 prefs
.style_namelistgad
? input_style
: NULL
);
2914 chanview_set_callbacks (gui
->chanview
, mg_switch_tab_cb
, mg_xbutton_cb
,
2915 mg_tab_contextmenu_cb
, (void *)mg_tabs_compare
);
2916 mg_place_userlist_and_chanview (gui
);
2920 mg_tabwin_focus_cb (GtkWindow
* win
, GdkEventFocus
*event
, gpointer userdata
)
2922 current_sess
= current_tab
;
2925 gtk_xtext_check_marker_visibility (GTK_XTEXT (current_sess
->gui
->xtext
));
2926 plugin_emit_dummy_print (current_sess
, "Focus Window");
2929 unflash_window (GTK_WIDGET (win
));
2935 mg_topwin_focus_cb (GtkWindow
* win
, GdkEventFocus
*event
, session
*sess
)
2937 current_sess
= sess
;
2938 if (!sess
->server
->server_session
)
2939 sess
->server
->server_session
= sess
;
2940 gtk_xtext_check_marker_visibility(GTK_XTEXT (current_sess
->gui
->xtext
));
2942 unflash_window (GTK_WIDGET (win
));
2944 plugin_emit_dummy_print (sess
, "Focus Window");
2949 mg_create_menu (session_gui
*gui
, GtkWidget
*table
, int away_state
)
2951 GtkAccelGroup
*accel_group
;
2953 accel_group
= gtk_accel_group_new ();
2954 gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel (table
)),
2956 g_object_unref (accel_group
);
2958 gui
->menu
= menu_create_main (accel_group
, TRUE
, away_state
, !gui
->is_tab
,
2960 gtk_table_attach (GTK_TABLE (table
), gui
->menu
, 0, 3, 0, 1,
2961 GTK_EXPAND
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
2965 mg_create_irctab (session
*sess
, GtkWidget
*table
)
2968 session_gui
*gui
= sess
->gui
;
2970 vbox
= gtk_vbox_new (FALSE
, 0);
2971 gtk_table_attach (GTK_TABLE (table
), vbox
, 1, 2, 2, 3,
2972 GTK_EXPAND
| GTK_FILL
, GTK_EXPAND
| GTK_FILL
, 0, 0);
2973 mg_create_center (sess
, gui
, vbox
);
2977 mg_create_topwindow (session
*sess
)
2982 if (sess
->type
== SESS_DIALOG
)
2983 win
= gtkutil_window_new ("XChat", NULL
,
2984 prefs
.dialog_width
, prefs
.dialog_height
, 0);
2986 win
= gtkutil_window_new ("XChat", NULL
,
2987 prefs
.mainwindow_width
,
2988 prefs
.mainwindow_height
, 0);
2989 sess
->gui
->window
= win
;
2990 gtk_container_set_border_width (GTK_CONTAINER (win
), GUI_BORDER
);
2992 g_signal_connect (G_OBJECT (win
), "focus_in_event",
2993 G_CALLBACK (mg_topwin_focus_cb
), sess
);
2994 g_signal_connect (G_OBJECT (win
), "destroy",
2995 G_CALLBACK (mg_topdestroy_cb
), sess
);
2996 g_signal_connect (G_OBJECT (win
), "configure_event",
2997 G_CALLBACK (mg_configure_cb
), sess
);
2999 palette_alloc (win
);
3001 table
= gtk_table_new (4, 3, FALSE
);
3002 /* spacing under the menubar */
3003 gtk_table_set_row_spacing (GTK_TABLE (table
), 0, GUI_SPACING
);
3004 /* left and right borders */
3005 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 1);
3006 gtk_table_set_col_spacing (GTK_TABLE (table
), 1, 1);
3007 gtk_container_add (GTK_CONTAINER (win
), table
);
3009 mg_create_irctab (sess
, table
);
3010 mg_create_menu (sess
->gui
, table
, sess
->server
->is_away
);
3012 if (sess
->res
->buffer
== NULL
)
3014 sess
->res
->buffer
= gtk_xtext_buffer_new (GTK_XTEXT (sess
->gui
->xtext
));
3015 gtk_xtext_buffer_show (GTK_XTEXT (sess
->gui
->xtext
), sess
->res
->buffer
, TRUE
);
3016 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
3017 sess
->res
->user_model
= userlist_create_model ();
3020 userlist_show (sess
);
3022 gtk_widget_show_all (table
);
3025 gtk_widget_hide (sess
->gui
->menu
);
3027 if (!prefs
.topicbar
)
3028 gtk_widget_hide (sess
->gui
->topic_bar
);
3030 if (!prefs
.userlistbuttons
)
3031 gtk_widget_hide (sess
->gui
->button_box
);
3033 if (prefs
.gui_tweaks
& 2)
3034 gtk_widget_hide (sess
->gui
->nick_box
);
3036 mg_decide_userlist (sess
, FALSE
);
3038 if (sess
->type
== SESS_DIALOG
)
3040 /* hide the chan-mode buttons */
3041 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3044 gtk_widget_hide (sess
->gui
->dialogbutton_box
);
3046 if (!prefs
.chanmodebuttons
)
3047 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3050 mg_place_userlist_and_chanview (sess
->gui
);
3052 gtk_widget_show (win
);
3056 mg_tabwindow_de_cb (GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
3061 if ((prefs
.gui_tray_flags
& 1) && tray_toggle_visibility (FALSE
))
3064 /* check for remaining toplevel windows */
3069 if (!sess
->gui
->is_tab
)
3074 mg_open_quit_dialog (TRUE
);
3079 mg_create_tabwindow (session
*sess
)
3084 win
= gtkutil_window_new ("XChat", NULL
, prefs
.mainwindow_width
,
3085 prefs
.mainwindow_height
, 0);
3086 sess
->gui
->window
= win
;
3087 gtk_window_move (GTK_WINDOW (win
), prefs
.mainwindow_left
,
3088 prefs
.mainwindow_top
);
3089 if (prefs
.gui_win_state
)
3090 gtk_window_maximize (GTK_WINDOW (win
));
3091 gtk_container_set_border_width (GTK_CONTAINER (win
), GUI_BORDER
);
3093 g_signal_connect (G_OBJECT (win
), "delete_event",
3094 G_CALLBACK (mg_tabwindow_de_cb
), 0);
3095 g_signal_connect (G_OBJECT (win
), "destroy",
3096 G_CALLBACK (mg_tabwindow_kill_cb
), 0);
3097 g_signal_connect (G_OBJECT (win
), "focus_in_event",
3098 G_CALLBACK (mg_tabwin_focus_cb
), NULL
);
3099 g_signal_connect (G_OBJECT (win
), "configure_event",
3100 G_CALLBACK (mg_configure_cb
), NULL
);
3101 g_signal_connect (G_OBJECT (win
), "window_state_event",
3102 G_CALLBACK (mg_windowstate_cb
), NULL
);
3104 palette_alloc (win
);
3106 sess
->gui
->main_table
= table
= gtk_table_new (4, 3, FALSE
);
3107 /* spacing under the menubar */
3108 gtk_table_set_row_spacing (GTK_TABLE (table
), 0, GUI_SPACING
);
3109 /* left and right borders */
3110 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 1);
3111 gtk_table_set_col_spacing (GTK_TABLE (table
), 1, 1);
3112 gtk_container_add (GTK_CONTAINER (win
), table
);
3114 mg_create_irctab (sess
, table
);
3115 mg_create_tabs (sess
->gui
);
3116 mg_create_menu (sess
->gui
, table
, sess
->server
->is_away
);
3120 gtk_widget_show_all (table
);
3123 gtk_widget_hide (sess
->gui
->menu
);
3125 mg_decide_userlist (sess
, FALSE
);
3127 if (!prefs
.topicbar
)
3128 gtk_widget_hide (sess
->gui
->topic_bar
);
3130 if (!prefs
.chanmodebuttons
)
3131 gtk_widget_hide (sess
->gui
->topicbutton_box
);
3133 if (!prefs
.userlistbuttons
)
3134 gtk_widget_hide (sess
->gui
->button_box
);
3136 if (prefs
.gui_tweaks
& 2)
3137 gtk_widget_hide (sess
->gui
->nick_box
);
3139 mg_place_userlist_and_chanview (sess
->gui
);
3141 gtk_widget_show (win
);
3145 mg_apply_setup (void)
3147 GSList
*list
= sess_list
;
3149 int done_main
= FALSE
;
3151 mg_create_tab_colors ();
3156 gtk_xtext_set_time_stamp (sess
->res
->buffer
, prefs
.timestamp
);
3157 ((xtext_buffer
*)sess
->res
->buffer
)->needs_recalc
= TRUE
;
3158 if (!sess
->gui
->is_tab
|| !done_main
)
3159 mg_place_userlist_and_chanview (sess
->gui
);
3160 if (sess
->gui
->is_tab
)
3167 mg_add_generic_tab (char *name
, char *title
, void *family
, GtkWidget
*box
)
3171 gtk_notebook_append_page (GTK_NOTEBOOK (mg_gui
->note_book
), box
, NULL
);
3172 gtk_widget_show (box
);
3174 ch
= chanview_add (mg_gui
->chanview
, name
, NULL
, box
, TRUE
, TAG_UTIL
, pix_util
);
3175 chan_set_color (ch
, plain_list
);
3176 /* FIXME: memory leak */
3177 g_object_set_data (G_OBJECT (box
), "title", strdup (title
));
3178 g_object_set_data (G_OBJECT (box
), "ch", ch
);
3180 if (prefs
.newtabstofront
)
3187 fe_buttons_update (session
*sess
)
3189 session_gui
*gui
= sess
->gui
;
3191 gtk_widget_destroy (gui
->button_box
);
3192 gui
->button_box
= mg_create_userlistbuttons (gui
->button_box_parent
);
3194 if (prefs
.userlistbuttons
)
3195 gtk_widget_show (sess
->gui
->button_box
);
3197 gtk_widget_hide (sess
->gui
->button_box
);
3201 fe_clear_channel (session
*sess
)
3203 char tbuf
[CHANLEN
+6];
3204 session_gui
*gui
= sess
->gui
;
3206 if (sess
->gui
->is_tab
)
3208 if (sess
->waitchannel
[0])
3210 if (prefs
.truncchans
> 2 && g_utf8_strlen (sess
->waitchannel
, -1) > prefs
.truncchans
)
3212 /* truncate long channel names */
3214 strcpy (tbuf
+ 1, sess
->waitchannel
);
3215 g_utf8_offset_to_pointer(tbuf
, prefs
.truncchans
)[0] = 0;
3216 strcat (tbuf
, "..)");
3219 sprintf (tbuf
, "(%s)", sess
->waitchannel
);
3223 strcpy (tbuf
, _("<none>"));
3224 chan_rename (sess
->res
->tab
, tbuf
, prefs
.truncchans
);
3227 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3229 gtk_entry_set_text (GTK_ENTRY (gui
->topic_entry
), "");
3233 gtk_widget_destroy (gui
->op_xpm
);
3238 if (sess
->res
->topic_text
)
3240 free (sess
->res
->topic_text
);
3241 sess
->res
->topic_text
= NULL
;
3247 fe_set_nonchannel (session
*sess
, int state
)
3252 fe_dlgbuttons_update (session
*sess
)
3255 session_gui
*gui
= sess
->gui
;
3257 gtk_widget_destroy (gui
->dialogbutton_box
);
3259 gui
->dialogbutton_box
= box
= gtk_hbox_new (0, 0);
3260 gtk_box_pack_start (GTK_BOX (gui
->topic_bar
), box
, 0, 0, 0);
3261 gtk_box_reorder_child (GTK_BOX (gui
->topic_bar
), box
, 3);
3262 mg_create_dialogbuttons (box
);
3264 gtk_widget_show_all (box
);
3266 if (current_tab
&& current_tab
->type
!= SESS_DIALOG
)
3267 gtk_widget_hide (current_tab
->gui
->dialogbutton_box
);
3271 fe_update_mode_buttons (session
*sess
, char mode
, char sign
)
3280 for (i
= 0; i
< NUM_FLAG_WIDS
- 1; i
++)
3282 if (chan_flags
[i
] == mode
)
3284 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3286 ignore_chanmode
= TRUE
;
3287 if (GTK_TOGGLE_BUTTON (sess
->gui
->flag_wid
[i
])->active
!= state
)
3288 gtk_toggle_button_set_active (
3289 GTK_TOGGLE_BUTTON (sess
->gui
->flag_wid
[i
]), state
);
3290 ignore_chanmode
= FALSE
;
3293 sess
->res
->flag_wid_state
[i
] = state
;
3301 fe_set_nick (server
*serv
, char *newnick
)
3303 GSList
*list
= sess_list
;
3309 if (sess
->server
== serv
)
3311 if (current_tab
== sess
|| !sess
->gui
->is_tab
)
3312 gtk_button_set_label (GTK_BUTTON (sess
->gui
->nick_label
), newnick
);
3319 fe_set_away (server
*serv
)
3321 GSList
*list
= sess_list
;
3327 if (sess
->server
== serv
)
3329 if (!sess
->gui
->is_tab
|| sess
== current_tab
)
3331 GTK_CHECK_MENU_ITEM (sess
->gui
->menu_item
[MENU_ID_AWAY
])->active
= serv
->is_away
;
3332 /* gray out my nickname */
3333 mg_set_myself_away (sess
->gui
, serv
->is_away
);
3341 fe_set_channel (session
*sess
)
3343 if (sess
->res
->tab
!= NULL
)
3344 chan_rename (sess
->res
->tab
, sess
->channel
, prefs
.truncchans
);
3348 mg_changui_new (session
*sess
, restore_gui
*res
, int tab
, int focus
)
3350 int first_run
= FALSE
;
3352 struct User
*user
= NULL
;
3356 res
= malloc (sizeof (restore_gui
));
3357 memset (res
, 0, sizeof (restore_gui
));
3362 if (!sess
->server
->front_session
)
3363 sess
->server
->front_session
= sess
;
3365 if (!is_channel (sess
->server
, sess
->channel
))
3366 user
= userlist_find_global (sess
->server
, sess
->channel
);
3370 gui
= malloc (sizeof (session_gui
));
3371 memset (gui
, 0, sizeof (session_gui
));
3372 gui
->is_tab
= FALSE
;
3374 mg_create_topwindow (sess
);
3375 fe_set_title (sess
);
3376 if (user
&& user
->hostname
)
3377 set_topic (sess
, user
->hostname
, user
->hostname
);
3384 gui
= &static_mg_gui
;
3385 memset (gui
, 0, sizeof (session_gui
));
3388 mg_create_tabwindow (sess
);
3390 parent_window
= gui
->window
;
3393 sess
->gui
= gui
= mg_gui
;
3397 if (user
&& user
->hostname
)
3398 set_topic (sess
, user
->hostname
, user
->hostname
);
3402 if (first_run
|| (prefs
.newtabstofront
== FOCUS_NEW_ONLY_ASKED
&& focus
)
3403 || prefs
.newtabstofront
== FOCUS_NEW_ALL
)
3404 chan_focus (res
->tab
);
3408 mg_create_generic_tab (char *name
, char *title
, int force_toplevel
,
3410 void *close_callback
, void *userdata
,
3411 int width
, int height
, GtkWidget
**vbox_ret
,
3414 GtkWidget
*vbox
, *win
;
3416 if (prefs
.tab_pos
== POS_HIDDEN
&& prefs
.windows_as_tabs
)
3417 prefs
.windows_as_tabs
= 0;
3419 if (force_toplevel
|| !prefs
.windows_as_tabs
)
3421 win
= gtkutil_window_new (title
, name
, width
, height
, 3);
3422 vbox
= gtk_vbox_new (0, 0);
3424 gtk_container_add (GTK_CONTAINER (win
), vbox
);
3425 gtk_widget_show (vbox
);
3427 g_signal_connect (G_OBJECT (win
), "destroy",
3428 G_CALLBACK (close_callback
), userdata
);
3432 vbox
= gtk_vbox_new (0, 2);
3433 g_object_set_data (G_OBJECT (vbox
), "w", GINT_TO_POINTER (width
));
3434 g_object_set_data (G_OBJECT (vbox
), "h", GINT_TO_POINTER (height
));
3435 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 3);
3439 g_signal_connect (G_OBJECT (vbox
), "destroy",
3440 G_CALLBACK (close_callback
), userdata
);
3442 mg_add_generic_tab (name
, title
, family
, vbox
);
3444 /* if (link_buttons)
3446 hbox = gtk_hbox_new (FALSE, 0);
3447 gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 0);
3448 mg_create_link_buttons (hbox, ch);
3449 gtk_widget_show (hbox);
3456 mg_move_tab (session
*sess
, int delta
)
3458 if (sess
->gui
->is_tab
)
3459 chan_move (sess
->res
->tab
, delta
);
3463 mg_move_tab_family (session
*sess
, int delta
)
3465 if (sess
->gui
->is_tab
)
3466 chan_move_family (sess
->res
->tab
, delta
);
3470 mg_set_title (GtkWidget
*vbox
, char *title
) /* for non-irc tab/window only */
3474 old
= g_object_get_data (G_OBJECT (vbox
), "title");
3477 g_object_set_data (G_OBJECT (vbox
), "title", strdup (title
));
3481 gtk_window_set_title (GTK_WINDOW (vbox
), title
);
3486 fe_server_callback (server
*serv
)
3490 if (serv
->gui
->chanlist_window
)
3491 mg_close_gen (NULL
, serv
->gui
->chanlist_window
);
3493 if (serv
->gui
->rawlog_window
)
3494 mg_close_gen (NULL
, serv
->gui
->rawlog_window
);
3499 /* called when a session is being killed */
3502 fe_session_callback (session
*sess
)
3504 if (sess
->res
->banlist_window
)
3505 mg_close_gen (NULL
, sess
->res
->banlist_window
);
3507 if (sess
->res
->input_text
)
3508 free (sess
->res
->input_text
);
3510 if (sess
->res
->topic_text
)
3511 free (sess
->res
->topic_text
);
3513 if (sess
->res
->limit_text
)
3514 free (sess
->res
->limit_text
);
3516 if (sess
->res
->key_text
)
3517 free (sess
->res
->key_text
);
3519 if (sess
->res
->queue_text
)
3520 free (sess
->res
->queue_text
);
3521 if (sess
->res
->queue_tip
)
3522 free (sess
->res
->queue_tip
);
3524 if (sess
->res
->lag_text
)
3525 free (sess
->res
->lag_text
);
3526 if (sess
->res
->lag_tip
)
3527 free (sess
->res
->lag_tip
);
3529 if (sess
->gui
->bartag
)
3530 fe_timeout_remove (sess
->gui
->bartag
);
3532 if (sess
->gui
!= &static_mg_gui
)
3537 /* ===== DRAG AND DROP STUFF ===== */
3540 is_child_of (GtkWidget
*widget
, GtkWidget
*parent
)
3544 if (widget
->parent
== parent
)
3546 widget
= widget
->parent
;
3552 mg_handle_drop (GtkWidget
*widget
, int y
, int *pos
, int *other_pos
)
3555 session_gui
*gui
= current_sess
->gui
;
3557 gdk_drawable_get_size (widget
->window
, NULL
, &height
);
3561 if (is_child_of (widget
, gui
->vpane_left
))
3562 *pos
= 1; /* top left */
3564 *pos
= 3; /* top right */
3568 if (is_child_of (widget
, gui
->vpane_left
))
3569 *pos
= 2; /* bottom left */
3571 *pos
= 4; /* bottom right */
3574 /* both in the same pos? must move one */
3575 if (*pos
== *other_pos
)
3594 mg_place_userlist_and_chanview (gui
);
3598 mg_is_gui_target (GdkDragContext
*context
)
3602 if (!context
|| !context
->targets
|| !context
->targets
->data
)
3605 target_name
= gdk_atom_name (context
->targets
->data
);
3608 /* if it's not XCHAT_CHANVIEW or XCHAT_USERLIST */
3609 /* we should ignore it. */
3610 if (target_name
[0] != 'X')
3612 g_free (target_name
);
3615 g_free (target_name
);
3621 /* this begin callback just creates an nice of the source */
3624 mg_drag_begin_cb (GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
3628 GdkPixbuf
*pix
, *pix2
;
3630 /* ignore file drops */
3631 if (!mg_is_gui_target (context
))
3634 cmap
= gtk_widget_get_colormap (widget
);
3635 gdk_drawable_get_size (widget
->window
, &width
, &height
);
3637 pix
= gdk_pixbuf_get_from_drawable (NULL
, widget
->window
, cmap
, 0, 0, 0, 0, width
, height
);
3638 pix2
= gdk_pixbuf_scale_simple (pix
, width
* 4 / 5, height
/ 2, GDK_INTERP_HYPER
);
3639 g_object_unref (pix
);
3641 gtk_drag_set_icon_pixbuf (context
, pix2
, 0, 0);
3642 g_object_set_data (G_OBJECT (widget
), "ico", pix2
);
3648 mg_drag_end_cb (GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
3650 /* ignore file drops */
3651 if (!mg_is_gui_target (context
))
3654 g_object_unref (g_object_get_data (G_OBJECT (widget
), "ico"));
3660 mg_drag_drop_cb (GtkWidget
*widget
, GdkDragContext
*context
, int x
, int y
, guint time
, gpointer user_data
)
3662 /* ignore file drops */
3663 if (!mg_is_gui_target (context
))
3666 switch (context
->action
)
3668 case GDK_ACTION_MOVE
:
3670 mg_handle_drop (widget
, y
, &prefs
.gui_ulist_pos
, &prefs
.tab_pos
);
3672 case GDK_ACTION_COPY
:
3673 /* from tree - we use GDK_ACTION_COPY for the tree */
3674 mg_handle_drop (widget
, y
, &prefs
.tab_pos
, &prefs
.gui_ulist_pos
);
3683 /* draw highlight rectangle in the destination */
3686 mg_drag_motion_cb (GtkWidget
*widget
, GdkDragContext
*context
, int x
, int y
, guint time
, gpointer scbar
)
3691 int half
, width
, height
;
3696 /* ignore file drops */
3697 if (!mg_is_gui_target (context
))
3700 if (scbar
) /* scrollbar */
3702 ox
= widget
->allocation
.x
;
3703 oy
= widget
->allocation
.y
;
3704 width
= widget
->allocation
.width
;
3705 height
= widget
->allocation
.height
;
3706 draw
= widget
->window
;
3711 gdk_drawable_get_size (widget
->window
, &width
, &height
);
3712 draw
= widget
->window
;
3715 val
.subwindow_mode
= GDK_INCLUDE_INFERIORS
;
3716 val
.graphics_exposures
= 0;
3717 val
.function
= GDK_XOR
;
3719 gc
= gdk_gc_new_with_values (widget
->window
, &val
, GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
| GDK_GC_FUNCTION
);
3720 col
.red
= rand() % 0xffff;
3721 col
.green
= rand() % 0xffff;
3722 col
.blue
= rand() % 0xffff;
3723 gdk_colormap_alloc_color (gtk_widget_get_colormap (widget
), &col
, FALSE
, TRUE
);
3724 gdk_gc_set_foreground (gc
, &col
);
3729 /* are both tree/userlist on the same side? */
3730 paned
= (GtkPaned
*)widget
->parent
->parent
;
3731 if (paned
->child1
!= NULL
&& paned
->child2
!= NULL
)
3733 gdk_draw_rectangle (draw
, gc
, 0, 1, 2, width
- 3, height
- 4);
3734 gdk_draw_rectangle (draw
, gc
, 0, 0, 1, width
- 1, height
- 2);
3735 g_object_unref (gc
);
3742 gdk_draw_rectangle (draw
, gc
, FALSE
, 1 + ox
, 2 + oy
, width
- 3, half
- 4);
3743 gdk_draw_rectangle (draw
, gc
, FALSE
, 0 + ox
, 1 + oy
, width
- 1, half
- 2);
3744 gtk_widget_queue_draw_area (widget
, ox
, half
+ oy
, width
, height
- half
);
3748 gdk_draw_rectangle (draw
, gc
, FALSE
, 0 + ox
, half
+ 1 + oy
, width
- 1, half
- 2);
3749 gdk_draw_rectangle (draw
, gc
, FALSE
, 1 + ox
, half
+ 2 + oy
, width
- 3, half
- 4);
3750 gtk_widget_queue_draw_area (widget
, ox
, oy
, width
, half
);
3753 g_object_unref (gc
);