restructure configure so pkg-config derived SSL flags get used
[rofl0r-ixchat.git] / src / fe-gtk / maingui.c
bloba22a93ccc1d33517226533e13263b46e4cca3df6
1 /* X-Chat
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
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <ctype.h>
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"
57 #include "fe-gtk.h"
58 #include "banlist.h"
59 #include "gtkutil.h"
60 #include "joind.h"
61 #include "palette.h"
62 #include "maingui.h"
63 #include "menu.h"
64 #include "fkeys.h"
65 #include "userlistgui.h"
66 #include "chanview.h"
67 #include "pixmaps.h"
68 #include "plugin-tray.h"
69 #include "xtext.h"
71 #ifdef USE_GTKSPELL
72 #include <gtk/gtktextview.h>
73 #include <gtkspell/gtkspell.h>
74 #endif
76 #ifdef USE_LIBSEXY
77 #include "sexy-spell-entry.h"
78 #endif
80 #define GUI_SPACING (3)
81 #define GUI_BORDER (0)
82 #define SCROLLBAR_SPACING (2)
84 enum
86 POS_INVALID = 0,
87 POS_TOPLEFT = 1,
88 POS_BOTTOMLEFT = 2,
89 POS_TOPRIGHT = 3,
90 POS_BOTTOMRIGHT = 4,
91 POS_TOP = 5, /* for tabs only */
92 POS_BOTTOM = 6,
93 POS_HIDDEN = 7
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;
120 #ifdef USE_GTKSPELL
122 /* use these when it's a GtkTextView instead of GtkEntry */
124 char *
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);
133 g_free (last);
134 last = gtk_text_buffer_get_text (buf, &start_iter, &end_iter, FALSE);
135 return last;
138 void
139 SPELL_ENTRY_SET_POS (GtkWidget *entry, int pos)
141 GtkTextIter iter;
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)
151 GtkTextIter cursor;
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);
158 void
159 SPELL_ENTRY_INSERT (GtkWidget *entry, const char *text, int len, int *pos)
161 GtkTextIter iter;
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);
170 #endif
172 static PangoAttrList *
173 mg_attr_list_create (GdkColor *col, int size)
175 PangoAttribute *attr;
176 PangoAttrList *list;
178 list = pango_attr_list_new ();
180 if (col)
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);
188 if (size > 0)
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);
196 return list;
199 static void
200 mg_create_tab_colors (void)
202 if (plain_list)
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);
218 #ifdef USE_XLIB
219 #include <gdk/gdkx.h>
221 static void
222 set_window_urgency (GtkWidget *win, gboolean set)
224 XWMHints *hints;
226 hints = XGetWMHints(GDK_WINDOW_XDISPLAY(win->window), GDK_WINDOW_XWINDOW(win->window));
227 if (set)
228 hints->flags |= XUrgencyHint;
229 else
230 hints->flags &= ~XUrgencyHint;
231 XSetWMHints(GDK_WINDOW_XDISPLAY(win->window),
232 GDK_WINDOW_XWINDOW(win->window), hints);
233 XFree(hints);
236 static void
237 flash_window (GtkWidget *win)
239 set_window_urgency (win, TRUE);
242 static void
243 unflash_window (GtkWidget *win)
245 set_window_urgency (win, FALSE);
247 #endif
249 /* flash the taskbar button */
251 void
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);
257 #endif
260 /* set a tab plain, red, light-red, or blue */
262 void
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))
268 switch (col)
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);
275 break;
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);
291 break;
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);
306 break;
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);
321 break;
326 static void
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 */
335 void
336 mg_set_access_icon (session_gui *gui, GdkPixbuf *pix, gboolean away)
338 if (gui->op_xpm)
340 if (pix == gtk_image_get_pixbuf (GTK_IMAGE (gui->op_xpm))) /* no change? */
342 mg_set_myself_away (gui, away);
343 return;
346 gtk_widget_destroy (gui->op_xpm);
347 gui->op_xpm = NULL;
350 if (pix)
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);
360 static gboolean
361 mg_inputbox_focus (GtkWidget *widget, GdkEventFocus *event, session_gui *gui)
363 GSList *list;
364 session *sess;
366 if (gui->is_tab)
367 return FALSE;
369 list = sess_list;
370 while (list)
372 sess = list->data;
373 if (sess->gui == gui)
375 current_sess = sess;
376 if (!sess->server->server_session)
377 sess->server->server_session = sess;
378 break;
380 list = list->next;
383 return FALSE;
386 void
387 mg_inputbox_cb (GtkWidget *igad, session_gui *gui)
389 char *cmd;
390 static int ignore = FALSE;
391 GSList *list;
392 session *sess = NULL;
394 if (ignore)
395 return;
397 cmd = SPELL_ENTRY_GET_TEXT (igad);
398 if (cmd[0] == 0)
399 return;
401 cmd = strdup (cmd);
403 /* avoid recursive loop */
404 ignore = TRUE;
405 SPELL_ENTRY_SET_TEXT (igad, "");
406 ignore = FALSE;
408 /* where did this event come from? */
409 if (gui->is_tab)
411 sess = current_tab;
412 } else
414 list = sess_list;
415 while (list)
417 sess = list->data;
418 if (sess->gui == gui)
419 break;
420 list = list->next;
422 if (!list)
423 sess = NULL;
426 if (sess)
427 handle_multiline (sess, cmd, TRUE, FALSE);
429 free (cmd);
432 static gboolean
433 has_key (char *modes)
435 if (!modes)
436 return FALSE;
437 /* this is a crude check, but "-k" can't exist, so it works. */
438 while (*modes)
440 if (*modes == 'k')
441 return TRUE;
442 if (*modes == ' ')
443 return FALSE;
444 modes++;
446 return FALSE;
449 void
450 fe_set_title (session *sess)
452 char tbuf[512];
453 int type;
455 if (sess->gui->is_tab && sess != current_tab)
456 return;
458 type = sess->type;
460 if (sess->server->connected == FALSE && sess->type != SESS_DIALOG)
461 goto def;
463 switch (type)
465 case SESS_DIALOG:
466 snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s %s @ %s",
467 _("Dialog with"), sess->channel, server_get_network (sess->server, TRUE));
468 break;
469 case SESS_SERVER:
470 snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s",
471 sess->server->nick, server_get_network (sess->server, TRUE));
472 break;
473 case SESS_CHANNEL:
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),
479 sess->channel);
480 else
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);
487 break;
488 case SESS_NOTICES:
489 case SESS_SNOTICES:
490 snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s (notices)",
491 sess->server->nick, server_get_network (sess->server, TRUE));
492 break;
493 default:
494 def:
495 gtk_window_set_title (GTK_WINDOW (sess->gui->window), DISPLAY_NAME);
496 return;
499 gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf);
502 static gboolean
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);
517 return FALSE;
520 static gboolean
521 mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
523 if (sess == NULL) /* for the main_window */
525 if (mg_gui)
527 if (prefs.mainwindow_save)
529 sess = current_sess;
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);
538 if (sess)
540 if (sess->type == SESS_DIALOG && prefs.mainwindow_save)
542 gtk_window_get_position (GTK_WINDOW (wid), &prefs.dialog_left,
543 &prefs.dialog_top);
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);
552 return FALSE;
555 /* move to a non-irc tab */
557 static void
558 mg_show_generic_tab (GtkWidget *box)
560 int num;
561 GtkWidget *f = NULL;
563 #if defined(GTK_WIDGET_HAS_FOCUS)
564 if (current_sess && GTK_WIDGET_HAS_FOCUS (current_sess->gui->input_box))
565 #else
566 if (current_sess && gtk_widget_has_focus (current_sess->gui->input_box))
567 #endif
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);
577 if (f)
578 gtk_widget_grab_focus (f);
581 /* a channel has been focused */
583 static void
584 mg_focus (session *sess)
586 if (sess->gui->is_tab)
587 current_tab = sess;
588 current_sess = sess;
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;
601 } else
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. */
613 if (sess->res->tab)
614 fe_set_tab_color (sess, 0);
618 static int
619 mg_progressbar_update (GtkWidget *bar)
621 static int type = 0;
622 static float pos = 0;
624 pos += 0.05;
625 if (pos >= 0.99)
627 if (type == 0)
629 type = 1;
630 gtk_progress_bar_set_orientation ((GtkProgressBar *) bar,
631 GTK_PROGRESS_RIGHT_TO_LEFT);
632 } else
634 type = 0;
635 gtk_progress_bar_set_orientation ((GtkProgressBar *) bar,
636 GTK_PROGRESS_LEFT_TO_RIGHT);
638 pos = 0.05;
640 gtk_progress_bar_set_fraction ((GtkProgressBar *) bar, pos);
641 return 1;
644 void
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);
653 void
654 mg_progressbar_destroy (session_gui *gui)
656 fe_timeout_remove (gui->bartag);
657 gtk_widget_destroy (gui->bar);
658 gui->bar = 0;
659 gui->bartag = 0;
662 /* switching tabs away from this one, so remember some info about it! */
664 static void
665 mg_unpopulate (session *sess)
667 restore_gui *res;
668 session_gui *gui;
669 int i;
671 gui = sess->gui;
672 res = sess->res;
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);
678 if (gui->laginfo)
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);
687 if (gui->lagometer)
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));
694 if (gui->bar)
696 res->c_graph = TRUE; /* still have a graph, just not visible now */
697 mg_progressbar_destroy (gui);
701 static void
702 mg_restore_label (GtkWidget *label, char **text)
704 if (!label)
705 return;
707 if (*text)
709 gtk_label_set_text (GTK_LABEL (label), *text);
710 free (*text);
711 *text = NULL;
712 } else
714 gtk_label_set_text (GTK_LABEL (label), "");
718 static void
719 mg_restore_entry (GtkWidget *entry, char **text)
721 if (*text)
723 gtk_entry_set_text (GTK_ENTRY (entry), *text);
724 free (*text);
725 *text = NULL;
726 } else
728 gtk_entry_set_text (GTK_ENTRY (entry), "");
730 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
733 static void
734 mg_restore_speller (GtkWidget *entry, char **text)
736 if (*text)
738 SPELL_ENTRY_SET_TEXT (entry, *text);
739 free (*text);
740 *text = NULL;
741 } else
743 SPELL_ENTRY_SET_TEXT (entry, "");
745 SPELL_ENTRY_SET_POS (entry, -1);
748 void
749 mg_set_topic_tip (session *sess)
751 char *text;
753 switch (sess->type)
755 case SESS_CHANNEL:
756 if (sess->topic)
758 text = g_strdup_printf (_("Topic for %s is: %s"), sess->channel,
759 sess->topic);
760 add_tip (sess->gui->topic_entry, text);
761 g_free (text);
762 } else
763 add_tip (sess->gui->topic_entry, _("No topic is set"));
764 break;
765 default:
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);
769 else
770 add_tip (sess->gui->topic_entry, NULL);
774 static void
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)))
780 #else
781 if ((pane->child1 == NULL || !gtk_widget_get_visible (pane->child1)) &&
782 (pane->child2 == NULL || !gtk_widget_get_visible (pane->child2)))
783 #endif
785 gtk_widget_hide (GTK_WIDGET (pane));
786 return;
789 gtk_widget_show (GTK_WIDGET (pane));
792 static void
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);
800 static void
801 mg_userlist_showhide (session *sess, int show)
803 session_gui *gui = sess->gui;
804 int handle_size;
806 if (show)
808 gtk_widget_show (gui->user_box);
809 gui->ul_hidden = 0;
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));
814 else
816 gtk_widget_hide (gui->user_box);
817 gui->ul_hidden = 1;
820 mg_hide_empty_boxes (gui);
823 static gboolean
824 mg_is_userlist_and_tree_combined (void)
826 if (prefs.tab_pos == POS_TOPLEFT && prefs.gui_ulist_pos == POS_BOTTOMLEFT)
827 return TRUE;
828 if (prefs.tab_pos == POS_BOTTOMLEFT && prefs.gui_ulist_pos == POS_TOPLEFT)
829 return TRUE;
831 if (prefs.tab_pos == POS_TOPRIGHT && prefs.gui_ulist_pos == POS_BOTTOMRIGHT)
832 return TRUE;
833 if (prefs.tab_pos == POS_BOTTOMRIGHT && prefs.gui_ulist_pos == POS_TOPRIGHT)
834 return TRUE;
836 return FALSE;
839 /* decide if the userlist should be shown or hidden for this tab */
841 void
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)
846 sess = current_tab;
848 if (prefs.hideuserlist)
850 mg_userlist_showhide (sess, FALSE);
851 return;
854 switch (sess->type)
856 case SESS_SERVER:
857 case SESS_DIALOG:
858 case SESS_NOTICES:
859 case SESS_SNOTICES:
860 if (mg_is_userlist_and_tree_combined ())
861 mg_userlist_showhide (sess, TRUE); /* show */
862 else
863 mg_userlist_showhide (sess, FALSE); /* hide */
864 break;
865 default:
866 mg_userlist_showhide (sess, TRUE); /* show */
870 static void
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;
880 static gboolean
881 mg_populate_userlist (session *sess)
883 session_gui *gui;
885 if (!sess)
886 sess = current_tab;
888 if (is_session (sess))
890 gui = sess->gui;
891 if (sess->type == SESS_DIALOG)
892 mg_set_access_icon (sess->gui, NULL, sess->server->is_away);
893 else
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);
899 ul_tag = 0;
900 return 0;
903 /* fill the irc tab with a new channel */
905 static void
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;
913 switch (sess->type)
915 case SESS_DIALOG:
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);
924 break;
925 case SESS_SERVER:
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);
934 break;
935 default:
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 */
947 if (gui->is_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)
953 render = FALSE;
955 gtk_xtext_buffer_show (GTK_XTEXT (gui->xtext), res->buffer, render);
957 if (gui->is_tab)
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);
968 mg_focus (sess);
969 fe_set_title (sess);
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 */
976 if (!gui->is_tab)
978 mg_populate_userlist (sess);
979 } else
981 if (ul_tag == 0)
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;
994 if (gui->lagometer)
996 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (gui->lagometer),
997 res->lag_value);
998 if (res->lag_tip)
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),
1004 res->queue_value);
1005 if (res->queue_tip)
1006 add_tip (sess->gui->throttlemeter->parent, res->queue_tip);
1009 /* did this tab have a connecting graph? restore it.. */
1010 if (res->c_graph)
1012 res->c_graph = FALSE;
1013 mg_progressbar_create (gui);
1016 /* menu items */
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");
1028 void
1029 mg_bring_tofront_sess (session *sess) /* IRC tab or window */
1031 if (sess->gui->is_tab)
1032 chan_focus (sess->res->tab);
1033 else
1034 gtk_window_present (GTK_WINDOW (sess->gui->window));
1037 void
1038 mg_bring_tofront (GtkWidget *vbox) /* non-IRC tab or window */
1040 chan *ch;
1042 ch = g_object_get_data (G_OBJECT (vbox), "ch");
1043 if (ch)
1044 chan_focus (ch);
1045 else
1046 gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (vbox)));
1049 void
1050 mg_switch_page (int relative, int num)
1052 if (mg_gui)
1053 chanview_move_focus (mg_gui->chanview, relative, num);
1056 /* a toplevel IRC window was destroyed */
1058 static void
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 */
1073 static void
1074 mg_ircdestroy (session *sess)
1076 GSList *list;
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 */
1085 if (mg_gui == NULL)
1087 /* puts("-> mg_gui is already NULL");*/
1088 return;
1091 list = sess_list;
1092 while (list)
1094 sess = list->data;
1095 if (sess->gui->is_tab)
1097 /* puts("-> some tabs still remain");*/
1098 return;
1100 list = list->next;
1103 /* puts("-> no tabs left, killing main tabwindow");*/
1104 gtk_widget_destroy (mg_gui->window);
1105 active_tab = NULL;
1106 mg_gui = NULL;
1107 parent_window = NULL;
1110 static void
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;)
1123 next = list->next;
1124 if (((session *)list->data)->server == sess->server &&
1125 ((session *)list->data) != sess)
1126 fe_close_window ((session *)list->data);
1127 list = next;
1130 /* just send one QUIT - better for BNCs */
1131 sess->server->sent_quit = FALSE;
1132 fe_close_window (sess);
1136 void
1137 mg_tab_close (session *sess)
1139 GtkWidget *dialog;
1140 GSList *list;
1141 int i;
1143 if (chan_remove (sess->res->tab, FALSE))
1144 mg_ircdestroy (sess);
1145 else
1147 for (i = 0, list = sess_list; list; list = list->next)
1148 if (((session *)list->data)->server == sess->server)
1149 i++;
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);
1160 else
1162 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1164 gtk_widget_show (dialog);
1168 static void
1169 mg_menu_destroy (GtkWidget *menu, gpointer userdata)
1171 gtk_widget_destroy (menu);
1172 g_object_unref (menu);
1175 void
1176 mg_create_icon_item (char *label, char *stock, GtkWidget *menu,
1177 void *callback, void *userdata)
1179 GtkWidget *item;
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),
1184 userdata);
1185 gtk_widget_show (item);
1188 static int
1189 mg_count_networks (void)
1191 int cons = 0;
1192 GSList *list;
1194 for (list = serv_list; list; list = list->next)
1196 if (((server *)list->data)->connected)
1197 cons++;
1199 return cons;
1202 static int
1203 mg_count_dccs (void)
1205 GSList *list;
1206 struct DCC *dcc;
1207 int dccs = 0;
1209 list = dcc_list;
1210 while (list)
1212 dcc = list->data;
1213 if ((dcc->type == TYPE_SEND || dcc->type == TYPE_RECV) &&
1214 dcc->dccstat == STAT_ACTIVE)
1215 dccs++;
1216 list = list->next;
1219 return dccs;
1222 void
1223 mg_open_quit_dialog (gboolean minimize_button)
1225 static GtkWidget *dialog = NULL;
1226 GtkWidget *dialog_vbox1;
1227 GtkWidget *table1;
1228 GtkWidget *image;
1229 GtkWidget *checkbutton1;
1230 GtkWidget *label;
1231 GtkWidget *dialog_action_area1;
1232 GtkWidget *button;
1233 char *text, *connecttext;
1234 int cons;
1235 int dccs;
1237 if (dialog)
1239 gtk_window_present (GTK_WINDOW (dialog));
1240 return;
1243 dccs = mg_count_dccs ();
1244 cons = mg_count_networks ();
1245 if (dccs + cons == 0 || !prefs.gui_quit_dialog)
1247 xchat_exit ();
1248 return;
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);
1287 g_free (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),
1298 GTK_BUTTONBOX_END);
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)))
1321 case 0:
1322 if (GTK_TOGGLE_BUTTON (checkbutton1)->active)
1323 prefs.gui_quit_dialog = 0;
1324 xchat_exit ();
1325 break;
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)
1335 prefs.gui_tray = 1;
1336 tray_apply_setup ();
1338 tray_toggle_visibility (TRUE);
1339 break;
1342 gtk_widget_destroy (dialog);
1343 dialog = NULL;
1346 void
1347 mg_close_sess (session *sess)
1349 if (sess_list->next == NULL)
1351 mg_open_quit_dialog (FALSE);
1352 return;
1355 fe_close_window (sess);
1358 static int
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);
1368 current_tab = NULL;
1369 active_tab = NULL;
1370 mg_gui = NULL;
1371 parent_window = NULL;
1372 return TRUE;
1374 return FALSE;
1377 /* destroy non-irc tab/window */
1379 static void
1380 mg_close_gen (chan *ch, GtkWidget *box)
1382 char *title = g_object_get_data (G_OBJECT (box), "title");
1384 if (title)
1385 free (title);
1386 if (!ch)
1387 ch = g_object_get_data (G_OBJECT (box), "ch");
1388 if (ch)
1390 /* remove from notebook */
1391 gtk_widget_destroy (box);
1392 /* remove the tab from chanview */
1393 mg_chan_remove (ch);
1394 } else
1396 gtk_widget_destroy (gtk_widget_get_toplevel (box));
1400 /* the "X" close button has been pressed (tab-view) */
1402 static void
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);
1411 static void
1412 mg_link_gentab (chan *ch, GtkWidget *box)
1414 int num;
1415 GtkWidget *win;
1417 g_object_ref (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);
1436 static void
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);
1443 return;
1446 /* userdata is GtkWidget * */
1447 mg_link_gentab (ch, chan_get_userdata (ch)); /* non-IRC tab */
1450 static void
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));
1457 static void
1458 mg_color_insert (GtkWidget *item, gpointer userdata)
1460 char buf[32];
1461 char *text;
1462 int num = GPOINTER_TO_INT (userdata);
1464 if (num > 99)
1466 switch (num)
1468 case 100:
1469 text = "\002"; break;
1470 case 101:
1471 text = "\037"; break;
1472 case 102:
1473 text = "\035"; break;
1474 default:
1475 text = "\017"; break;
1477 key_action_insert (current_sess->gui->input_box, 0, text, 0, 0);
1478 } else
1480 sprintf (buf, "\003%02d", num);
1481 key_action_insert (current_sess->gui->input_box, 0, buf, 0, 0);
1485 static void
1486 mg_markup_item (GtkWidget *menu, char *text, int arg)
1488 GtkWidget *item;
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);
1498 GtkWidget *
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);
1511 return submenu;
1514 static void
1515 mg_create_color_menu (GtkWidget *menu, session *sess)
1517 GtkWidget *submenu;
1518 GtkWidget *subsubmenu;
1519 char buf[256];
1520 int i;
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\">"
1534 " </span></tt>",
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\">"
1544 " </span></tt>",
1545 i, colors[i].red >> 8, colors[i].green >> 8, colors[i].blue >> 8);
1546 mg_markup_item (subsubmenu, buf, i);
1550 static void
1551 mg_set_guint8 (GtkCheckMenuItem *item, guint8 *setting)
1553 session *sess = current_sess;
1554 guint8 logging = sess->text_logging;
1556 *setting = SET_OFF;
1557 if (item->active)
1558 *setting = SET_ON;
1560 /* has the logging setting changed? */
1561 if (logging != sess->text_logging)
1562 log_open_or_close (sess);
1565 static void
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);
1577 static void
1578 mg_create_perchannelmenu (session *sess, GtkWidget *menu)
1580 GtkWidget *submenu;
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);
1590 static void
1591 mg_create_alertmenu (session *sess, GtkWidget *menu)
1593 GtkWidget *submenu;
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);
1602 static void
1603 mg_create_tabmenu (session *sess, GdkEventButton *event, chan *ch)
1605 GtkWidget *menu, *item;
1606 char buf[256];
1608 menu = gtk_menu_new ();
1610 if (sess)
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);
1614 g_free (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);
1621 /* separator */
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);
1630 /* separator */
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);
1645 if (event->window)
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);
1655 static gboolean
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);
1662 return FALSE;
1665 if (event->button != 3)
1666 return FALSE;
1668 if (tag == TAG_IRC)
1669 mg_create_tabmenu (ud, event, ch);
1670 else
1671 mg_create_tabmenu (NULL, event, ch);
1673 return TRUE;
1676 void
1677 mg_dnd_drop_file (session *sess, char *target, char *uri)
1679 char *p, *data, *next, *fname;
1681 p = data = strdup (uri);
1682 while (*p)
1684 next = strchr (p, '\r');
1685 if (strncasecmp ("file:", p, 5) == 0)
1687 if (next)
1688 *next = 0;
1689 fname = g_filename_from_uri (p, NULL, NULL);
1690 if (fname)
1692 /* dcc_send() expects utf-8 */
1693 p = xchat_filename_to_utf8 (fname, -1, 0, 0, 0);
1694 if (p)
1696 dcc_send (sess, target, p, prefs.dcc_max_send_cps, 0);
1697 g_free (p);
1699 g_free (fname);
1702 if (!next)
1703 break;
1704 p = next + 1;
1705 if (*p == '\n')
1706 p++;
1708 free (data);
1712 static void
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 */
1724 static void
1725 mg_add_chan (session *sess)
1727 GdkPixbuf *icon;
1728 char *name = _("<none>");
1730 if (sess->channel[0])
1731 name = sess->channel;
1733 switch (sess->type)
1735 case SESS_CHANNEL:
1736 icon = pix_channel;
1737 break;
1738 case SESS_SERVER:
1739 icon = pix_server;
1740 break;
1741 default:
1742 icon = pix_dialog;
1745 sess->res->tab = chanview_add (sess->gui->chanview, name, sess->server, sess,
1746 sess->type == SESS_SERVER ? FALSE : TRUE,
1747 TAG_IRC, icon);
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 ();
1761 static void
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);
1772 static GtkWidget *
1773 mg_create_userlistbuttons (GtkWidget *box)
1775 struct popup *pop;
1776 GSList *list = button_list;
1777 int a = 0, b = 0;
1778 GtkWidget *tab;
1780 tab = gtk_table_new (5, 2, FALSE);
1781 gtk_box_pack_end (GTK_BOX (box), tab, FALSE, FALSE, 0);
1783 while (list)
1785 pop = list->data;
1786 if (pop->cmd[0])
1788 mg_userlist_button (tab, pop->name, pop->cmd, a, a + 1, b, b + 1);
1789 a++;
1790 if (a == 2)
1792 a = 0;
1793 b++;
1796 list = list->next;
1799 return tab;
1802 static void
1803 mg_topic_cb (GtkWidget *entry, gpointer userdata)
1805 session *sess = current_sess;
1806 char *text;
1808 if (sess->channel[0] && sess->server->connected && sess->type == SESS_CHANNEL)
1810 text = GTK_ENTRY (entry)->text;
1811 if (text[0] == 0)
1812 text = NULL;
1813 sess->server->p_topic (sess->server, sess->channel, text);
1814 } else
1815 gtk_entry_set_text (GTK_ENTRY (entry), "");
1816 /* restore focus to the input widget, where the next input will most
1817 likely be */
1818 gtk_widget_grab_focus (sess->gui->input_box);
1821 static void
1822 mg_tabwindow_kill_cb (GtkWidget *win, gpointer userdata)
1824 GSList *list, *next;
1825 session *sess;
1827 /* puts("enter mg_tabwindow_kill_cb");*/
1828 xchat_is_quitting = TRUE;
1830 /* see if there's any non-tab windows left */
1831 list = sess_list;
1832 while (list)
1834 sess = list->data;
1835 next = list->next;
1836 if (!sess->gui->is_tab)
1838 xchat_is_quitting = FALSE;
1839 /* puts("-> will not exit, some toplevel windows left");*/
1840 } else
1842 mg_ircdestroy (sess);
1844 list = next;
1847 current_tab = NULL;
1848 active_tab = NULL;
1849 mg_gui = NULL;
1850 parent_window = NULL;
1853 static GtkWidget *
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);
1868 } else
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;
1878 free (sess->gui);
1879 sess->gui = NULL;
1881 return ret;
1884 static void
1885 mg_link_irctab (session *sess, int focus)
1887 GtkWidget *win;
1889 if (sess->gui->is_tab)
1891 win = mg_changui_destroy (sess);
1892 mg_changui_new (sess, sess->res, 0, focus);
1893 mg_populate (sess);
1894 xchat_is_quitting = FALSE;
1895 if (win)
1896 gtk_widget_destroy (win);
1897 return;
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;
1905 if (win)
1906 gtk_widget_destroy (win);
1909 void
1910 mg_detach (session *sess, int mode)
1912 switch (mode)
1914 /* detach only */
1915 case 1:
1916 if (sess->gui->is_tab)
1917 mg_link_irctab (sess, 1);
1918 break;
1919 /* attach only */
1920 case 2:
1921 if (!sess->gui->is_tab)
1922 mg_link_irctab (sess, 1);
1923 break;
1924 /* toggle */
1925 default:
1926 mg_link_irctab (sess, 1);
1930 static int
1931 check_is_number (char *t)
1933 while (*t)
1935 if (*t < '0' || *t > '9')
1936 return FALSE;
1937 t++;
1939 return TRUE;
1942 static void
1943 mg_change_flag (GtkWidget * wid, session *sess, char flag)
1945 server *serv = sess->server;
1946 char mode[3];
1948 mode[1] = flag;
1949 mode[2] = '\0';
1950 if (serv->connected && sess->channel[0])
1952 if (GTK_TOGGLE_BUTTON (wid)->active)
1953 mode[0] = '+';
1954 else
1955 mode[0] = '-';
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;
1963 static void
1964 flagl_hit (GtkWidget * wid, struct session *sess)
1966 char modes[512];
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);
1980 return;
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);
1986 } else
1987 mg_change_flag (wid, sess, 'l');
1990 static void
1991 flagk_hit (GtkWidget * wid, struct session *sess)
1993 char modes[512];
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)
2002 modes[0] = '+';
2004 serv->p_mode (serv, sess->channel, modes);
2008 static void
2009 mg_flagbutton_cb (GtkWidget *but, char *flag)
2011 session *sess;
2012 char mode;
2014 if (ignore_chanmode)
2015 return;
2017 sess = current_sess;
2018 mode = tolower ((unsigned char) flag[0]);
2020 switch (mode)
2022 case 'l':
2023 flagl_hit (but, sess);
2024 break;
2025 case 'k':
2026 flagk_hit (but, sess);
2027 break;
2028 case 'b':
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);
2033 break;
2034 default:
2035 mg_change_flag (but, sess, mode);
2039 static GtkWidget *
2040 mg_create_flagbutton (char *tip, GtkWidget *box, char *face)
2042 GtkWidget *wid;
2044 wid = gtk_toggle_button_new_with_label (face);
2045 gtk_widget_set_size_request (wid, 18, 0);
2046 add_tip (wid, tip);
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);
2052 return wid;
2055 static void
2056 mg_key_entry_cb (GtkWidget * igad, gpointer userdata)
2058 char modes[512];
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);
2071 static void
2072 mg_limit_entry_cb (GtkWidget * igad, gpointer userdata)
2074 char modes[512];
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);
2085 return;
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);
2094 static void
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);
2102 static void
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);
2138 /*static void
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);
2144 if (!userdata)
2145 gtkutil_button (box, GTK_STOCK_REDO, _("Attach/Detach this tab"),
2146 mg_link_cb, userdata, 0);
2149 static void
2150 mg_dialog_button_cb (GtkWidget *wid, char *cmd)
2152 /* the longest cmd is 12, and the longest nickname is 64 */
2153 char buf[128];
2154 char *host = "";
2155 char *topic;
2157 if (!current_sess)
2158 return;
2160 topic = (char *)(GTK_ENTRY (current_sess->gui->topic_entry)->text);
2161 topic = strrchr (topic, '@');
2162 if (topic)
2163 host = topic + 1;
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);
2177 static void
2178 mg_dialog_button (GtkWidget *box, char *name, char *cmd)
2180 GtkWidget *wid;
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);
2189 static void
2190 mg_create_dialogbuttons (GtkWidget *box)
2192 struct popup *pop;
2193 GSList *list = dlgbutton_list;
2195 while (list)
2197 pop = list->data;
2198 if (pop->cmd[0])
2199 mg_dialog_button (box, pop->name, pop->cmd);
2200 list = list->next;
2204 static void
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);
2213 if (!gui->is_tab)
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 */
2240 static int
2241 mg_word_check (GtkWidget * xtext, char *word, int len)
2243 session *sess = current_sess;
2244 int ret;
2246 ret = url_check_word (word, len); /* common/url.c */
2247 if (ret == 0)
2249 if (( (word[0]=='@' || word[0]=='+' || word[0]=='%') && userlist_find (sess, word+1)) || userlist_find (sess, word))
2250 return WORD_NICK;
2252 if (sess->type == SESS_DIALOG)
2253 return WORD_DIALOG;
2256 return ret;
2259 /* mouse click inside text area */
2261 static void
2262 mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
2264 session *sess = current_sess;
2266 if (even->button == 1) /* left button */
2268 if (word == NULL)
2270 mg_focus (sess);
2271 return;
2274 if ((even->state & 13) == prefs.gui_url_mod)
2276 switch (mg_word_check (xtext, word, strlen (word)))
2278 case WORD_URL:
2279 case WORD_HOST:
2280 fe_open_url (word);
2283 return;
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);
2292 return;
2295 switch (mg_word_check (xtext, word, strlen (word)))
2297 case 0:
2298 menu_middlemenu (sess, even);
2299 break;
2300 case WORD_URL:
2301 case WORD_HOST:
2302 menu_urlmenu (even, word);
2303 break;
2304 case WORD_NICK:
2305 menu_nickmenu (sess, even, (word[0]=='@' || word[0]=='+' || word[0]=='%') ?
2306 word+1 : word, FALSE);
2307 break;
2308 case WORD_CHANNEL:
2309 if (*word == '@' || *word == '+' || *word=='^' || *word=='%' || *word=='*')
2310 word++;
2311 menu_chanmenu (sess, even, word);
2312 break;
2313 case WORD_EMAIL:
2315 char *newword = malloc (strlen (word) + 10);
2316 if (*word == '~')
2317 word++;
2318 sprintf (newword, "mailto:%s", word);
2319 menu_urlmenu (even, newword);
2320 free (newword);
2322 break;
2323 case WORD_DIALOG:
2324 menu_nickmenu (sess, even, sess->channel, FALSE);
2325 break;
2329 void
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);
2345 exit (1);
2348 gtk_xtext_refresh (xtext, FALSE);
2351 /* handle errors reported by xtext */
2353 static void
2354 mg_xtext_error (int type)
2356 switch (type)
2358 case 0:
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 */
2367 static void
2368 mg_create_textarea (session *sess, GtkWidget *box)
2370 GtkWidget *inbox, *vbox, *frame;
2371 GtkXText *xtext;
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);
2425 static GtkWidget *
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);
2440 return label;
2443 static void
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");
2488 void
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);
2501 static void
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);
2530 static void
2531 mg_leftpane_cb (GtkPaned *pane, GParamSpec *param, session_gui *gui)
2533 prefs.gui_pane_left_size = gtk_paned_get_position (pane);
2536 static void
2537 mg_rightpane_cb (GtkPaned *pane, GParamSpec *param, session_gui *gui)
2539 int handle_size;
2541 /* if (pane->child1 == NULL || (!GTK_WIDGET_VISIBLE (pane->child1)))
2542 return;
2543 if (pane->child2 == NULL || (!GTK_WIDGET_VISIBLE (pane->child2)))
2544 return;*/
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;
2551 static gboolean
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);
2558 return FALSE;
2561 static void
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);
2584 else
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);
2613 static void
2614 mg_change_nick (int cancel, char *text, gpointer userdata)
2616 char buf[256];
2618 if (!cancel)
2620 snprintf (buf, sizeof (buf), "nick %s", text);
2621 handle_command (current_sess, buf, FALSE);
2625 static void
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 */
2634 static void
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)
2641 *cv = POS_TOPLEFT;
2644 /* userlist can't be on TOP or BOTTOM */
2645 if (*ul == POS_TOP || *ul == POS_BOTTOM)
2646 *ul = POS_TOPRIGHT;
2648 /* can't have both in the same place */
2649 if (*cv == *ul)
2651 *cv = POS_TOPRIGHT;
2652 if (*ul == POS_TOPRIGHT)
2653 *cv = POS_BOTTOMRIGHT;
2657 static void
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;
2678 if (chanview)
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)
2689 case POS_TOPLEFT:
2690 gtk_paned_pack1 (GTK_PANED (gui->vpane_left), chanview, FALSE, TRUE);
2691 break;
2692 case POS_BOTTOMLEFT:
2693 gtk_paned_pack2 (GTK_PANED (gui->vpane_left), chanview, FALSE, TRUE);
2694 break;
2695 case POS_TOPRIGHT:
2696 gtk_paned_pack1 (GTK_PANED (gui->vpane_right), chanview, FALSE, TRUE);
2697 break;
2698 case POS_BOTTOMRIGHT:
2699 gtk_paned_pack2 (GTK_PANED (gui->vpane_right), chanview, FALSE, TRUE);
2700 break;
2701 case POS_TOP:
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);
2705 break;
2706 case POS_HIDDEN:
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);
2713 else
2714 gtk_table_attach (GTK_TABLE (gui->main_table), chanview,
2715 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
2716 break;
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);
2724 if (userlist)
2726 switch (prefs.gui_ulist_pos)
2728 case POS_TOPLEFT:
2729 gtk_paned_pack1 (GTK_PANED (gui->vpane_left), userlist, FALSE, TRUE);
2730 break;
2731 case POS_BOTTOMLEFT:
2732 gtk_paned_pack2 (GTK_PANED (gui->vpane_left), userlist, FALSE, TRUE);
2733 break;
2734 case POS_BOTTOMRIGHT:
2735 gtk_paned_pack2 (GTK_PANED (gui->vpane_right), userlist, FALSE, TRUE);
2736 break;
2737 /*case POS_HIDDEN:
2738 break;*/ /* Hide using the VIEW menu instead */
2739 default:/* POS_TOPRIGHT */
2740 gtk_paned_pack1 (GTK_PANED (gui->vpane_right), userlist, FALSE, TRUE);
2744 if (unref_chanview)
2745 g_object_unref (chanview);
2746 if (unref_userlist)
2747 g_object_unref (userlist);
2749 mg_hide_empty_boxes (gui);
2752 static void
2753 mg_place_userlist_and_chanview (session_gui *gui)
2755 GtkOrientation orientation;
2756 GtkWidget *chanviewbox = NULL;
2757 int pos;
2759 mg_sanitize_positions (&prefs.tab_pos, &prefs.gui_ulist_pos);
2761 if (gui->chanview)
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);
2776 void
2777 mg_change_layout (int type)
2779 if (mg_gui)
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);
2790 static void
2791 mg_inputbox_rightclick (GtkEntry *entry, GtkWidget *menu)
2793 mg_create_color_menu (menu, NULL);
2796 static void
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);
2815 #ifdef USE_GTKSPELL
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),
2825 GTK_SHADOW_IN);
2826 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2827 GTK_POLICY_NEVER,
2828 GTK_POLICY_NEVER);
2829 gtk_container_add (GTK_CONTAINER (sw), entry);
2830 gtk_container_add (GTK_CONTAINER (hbox), sw);
2831 #else
2832 #ifdef USE_LIBSEXY
2833 gui->input_box = entry = sexy_spell_entry_new ();
2834 sexy_spell_entry_set_checked ((SexySpellEntry *)entry, prefs.gui_input_spell);
2835 #else
2836 gui->input_box = entry = gtk_entry_new ();
2837 #endif
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);
2842 #endif
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);
2857 static void
2858 mg_switch_tab_cb (chanview *cv, chan *ch, int tag, gpointer ud)
2860 chan *old;
2861 session *sess = ud;
2863 old = active_tab;
2864 active_tab = ch;
2866 if (tag == TAG_IRC)
2868 if (active_tab != old)
2870 if (old && current_tab)
2871 mg_unpopulate (current_tab);
2872 mg_populate (sess);
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) */
2885 static int
2886 mg_tabs_compare (session *a, session *b)
2888 /* server tabs always go first */
2889 if (a->type == SESS_SERVER)
2890 return -1;
2892 /* then channels */
2893 if (a->type == SESS_CHANNEL && b->type != SESS_CHANNEL)
2894 return -1;
2895 if (a->type != SESS_CHANNEL && b->type == SESS_CHANNEL)
2896 return 1;
2898 return strcasecmp (a->channel, b->channel);
2901 static void
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)
2909 use_icons = TRUE;
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);
2919 static gboolean
2920 mg_tabwin_focus_cb (GtkWindow * win, GdkEventFocus *event, gpointer userdata)
2922 current_sess = current_tab;
2923 if (current_sess)
2925 gtk_xtext_check_marker_visibility (GTK_XTEXT (current_sess->gui->xtext));
2926 plugin_emit_dummy_print (current_sess, "Focus Window");
2928 #ifdef USE_XLIB
2929 unflash_window (GTK_WIDGET (win));
2930 #endif
2931 return FALSE;
2934 static gboolean
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));
2941 #ifdef USE_XLIB
2942 unflash_window (GTK_WIDGET (win));
2943 #endif
2944 plugin_emit_dummy_print (sess, "Focus Window");
2945 return FALSE;
2948 static void
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)),
2955 accel_group);
2956 g_object_unref (accel_group);
2958 gui->menu = menu_create_main (accel_group, TRUE, away_state, !gui->is_tab,
2959 gui->menu_item);
2960 gtk_table_attach (GTK_TABLE (table), gui->menu, 0, 3, 0, 1,
2961 GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
2964 static void
2965 mg_create_irctab (session *sess, GtkWidget *table)
2967 GtkWidget *vbox;
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);
2976 static void
2977 mg_create_topwindow (session *sess)
2979 GtkWidget *win;
2980 GtkWidget *table;
2982 if (sess->type == SESS_DIALOG)
2983 win = gtkutil_window_new ("XChat", NULL,
2984 prefs.dialog_width, prefs.dialog_height, 0);
2985 else
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);
3024 if (prefs.hidemenu)
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);
3042 } else
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);
3055 static gboolean
3056 mg_tabwindow_de_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
3058 GSList *list;
3059 session *sess;
3061 if ((prefs.gui_tray_flags & 1) && tray_toggle_visibility (FALSE))
3062 return TRUE;
3064 /* check for remaining toplevel windows */
3065 list = sess_list;
3066 while (list)
3068 sess = list->data;
3069 if (!sess->gui->is_tab)
3070 return FALSE;
3071 list = list->next;
3074 mg_open_quit_dialog (TRUE);
3075 return TRUE;
3078 static void
3079 mg_create_tabwindow (session *sess)
3081 GtkWidget *win;
3082 GtkWidget *table;
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);
3118 mg_focus (sess);
3120 gtk_widget_show_all (table);
3122 if (prefs.hidemenu)
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);
3144 void
3145 mg_apply_setup (void)
3147 GSList *list = sess_list;
3148 session *sess;
3149 int done_main = FALSE;
3151 mg_create_tab_colors ();
3153 while (list)
3155 sess = list->data;
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)
3161 done_main = TRUE;
3162 list = list->next;
3166 static chan *
3167 mg_add_generic_tab (char *name, char *title, void *family, GtkWidget *box)
3169 chan *ch;
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)
3181 chan_focus (ch);
3183 return ch;
3186 void
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);
3196 else
3197 gtk_widget_hide (sess->gui->button_box);
3200 void
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 */
3213 tbuf[0] = '(';
3214 strcpy (tbuf + 1, sess->waitchannel);
3215 g_utf8_offset_to_pointer(tbuf, prefs.truncchans)[0] = 0;
3216 strcat (tbuf, "..)");
3217 } else
3219 sprintf (tbuf, "(%s)", sess->waitchannel);
3222 else
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), "");
3231 if (gui->op_xpm)
3233 gtk_widget_destroy (gui->op_xpm);
3234 gui->op_xpm = 0;
3236 } else
3238 if (sess->res->topic_text)
3240 free (sess->res->topic_text);
3241 sess->res->topic_text = NULL;
3246 void
3247 fe_set_nonchannel (session *sess, int state)
3251 void
3252 fe_dlgbuttons_update (session *sess)
3254 GtkWidget *box;
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);
3270 void
3271 fe_update_mode_buttons (session *sess, char mode, char sign)
3273 int state, i;
3275 if (sign == '+')
3276 state = TRUE;
3277 else
3278 state = FALSE;
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;
3291 } else
3293 sess->res->flag_wid_state[i] = state;
3295 return;
3300 void
3301 fe_set_nick (server *serv, char *newnick)
3303 GSList *list = sess_list;
3304 session *sess;
3306 while (list)
3308 sess = list->data;
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);
3314 list = list->next;
3318 void
3319 fe_set_away (server *serv)
3321 GSList *list = sess_list;
3322 session *sess;
3324 while (list)
3326 sess = list->data;
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);
3336 list = list->next;
3340 void
3341 fe_set_channel (session *sess)
3343 if (sess->res->tab != NULL)
3344 chan_rename (sess->res->tab, sess->channel, prefs.truncchans);
3347 void
3348 mg_changui_new (session *sess, restore_gui *res, int tab, int focus)
3350 int first_run = FALSE;
3351 session_gui *gui;
3352 struct User *user = NULL;
3354 if (!res)
3356 res = malloc (sizeof (restore_gui));
3357 memset (res, 0, sizeof (restore_gui));
3360 sess->res = res;
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);
3368 if (!tab)
3370 gui = malloc (sizeof (session_gui));
3371 memset (gui, 0, sizeof (session_gui));
3372 gui->is_tab = FALSE;
3373 sess->gui = gui;
3374 mg_create_topwindow (sess);
3375 fe_set_title (sess);
3376 if (user && user->hostname)
3377 set_topic (sess, user->hostname, user->hostname);
3378 return;
3381 if (mg_gui == NULL)
3383 first_run = TRUE;
3384 gui = &static_mg_gui;
3385 memset (gui, 0, sizeof (session_gui));
3386 gui->is_tab = TRUE;
3387 sess->gui = gui;
3388 mg_create_tabwindow (sess);
3389 mg_gui = gui;
3390 parent_window = gui->window;
3391 } else
3393 sess->gui = gui = mg_gui;
3394 gui->is_tab = TRUE;
3397 if (user && user->hostname)
3398 set_topic (sess, user->hostname, user->hostname);
3400 mg_add_chan (sess);
3402 if (first_run || (prefs.newtabstofront == FOCUS_NEW_ONLY_ASKED && focus)
3403 || prefs.newtabstofront == FOCUS_NEW_ALL )
3404 chan_focus (res->tab);
3407 GtkWidget *
3408 mg_create_generic_tab (char *name, char *title, int force_toplevel,
3409 int link_buttons,
3410 void *close_callback, void *userdata,
3411 int width, int height, GtkWidget **vbox_ret,
3412 void *family)
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);
3423 *vbox_ret = vbox;
3424 gtk_container_add (GTK_CONTAINER (win), vbox);
3425 gtk_widget_show (vbox);
3426 if (close_callback)
3427 g_signal_connect (G_OBJECT (win), "destroy",
3428 G_CALLBACK (close_callback), userdata);
3429 return win;
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);
3436 *vbox_ret = vbox;
3438 if (close_callback)
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);
3452 return vbox;
3455 void
3456 mg_move_tab (session *sess, int delta)
3458 if (sess->gui->is_tab)
3459 chan_move (sess->res->tab, delta);
3462 void
3463 mg_move_tab_family (session *sess, int delta)
3465 if (sess->gui->is_tab)
3466 chan_move_family (sess->res->tab, delta);
3469 void
3470 mg_set_title (GtkWidget *vbox, char *title) /* for non-irc tab/window only */
3472 char *old;
3474 old = g_object_get_data (G_OBJECT (vbox), "title");
3475 if (old)
3477 g_object_set_data (G_OBJECT (vbox), "title", strdup (title));
3478 free (old);
3479 } else
3481 gtk_window_set_title (GTK_WINDOW (vbox), title);
3485 void
3486 fe_server_callback (server *serv)
3488 joind_close (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);
3496 free (serv->gui);
3499 /* called when a session is being killed */
3501 void
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)
3533 free (sess->gui);
3534 free (sess->res);
3537 /* ===== DRAG AND DROP STUFF ===== */
3539 static gboolean
3540 is_child_of (GtkWidget *widget, GtkWidget *parent)
3542 while (widget)
3544 if (widget->parent == parent)
3545 return TRUE;
3546 widget = widget->parent;
3548 return FALSE;
3551 static void
3552 mg_handle_drop (GtkWidget *widget, int y, int *pos, int *other_pos)
3554 int height;
3555 session_gui *gui = current_sess->gui;
3557 gdk_drawable_get_size (widget->window, NULL, &height);
3559 if (y < height / 2)
3561 if (is_child_of (widget, gui->vpane_left))
3562 *pos = 1; /* top left */
3563 else
3564 *pos = 3; /* top right */
3566 else
3568 if (is_child_of (widget, gui->vpane_left))
3569 *pos = 2; /* bottom left */
3570 else
3571 *pos = 4; /* bottom right */
3574 /* both in the same pos? must move one */
3575 if (*pos == *other_pos)
3577 switch (*other_pos)
3579 case 1:
3580 *other_pos = 2;
3581 break;
3582 case 2:
3583 *other_pos = 1;
3584 break;
3585 case 3:
3586 *other_pos = 4;
3587 break;
3588 case 4:
3589 *other_pos = 3;
3590 break;
3594 mg_place_userlist_and_chanview (gui);
3597 static gboolean
3598 mg_is_gui_target (GdkDragContext *context)
3600 char *target_name;
3602 if (!context || !context->targets || !context->targets->data)
3603 return FALSE;
3605 target_name = gdk_atom_name (context->targets->data);
3606 if (target_name)
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);
3613 return FALSE;
3615 g_free (target_name);
3618 return TRUE;
3621 /* this begin callback just creates an nice of the source */
3623 gboolean
3624 mg_drag_begin_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata)
3626 int width, height;
3627 GdkColormap *cmap;
3628 GdkPixbuf *pix, *pix2;
3630 /* ignore file drops */
3631 if (!mg_is_gui_target (context))
3632 return FALSE;
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);
3644 return TRUE;
3647 void
3648 mg_drag_end_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata)
3650 /* ignore file drops */
3651 if (!mg_is_gui_target (context))
3652 return;
3654 g_object_unref (g_object_get_data (G_OBJECT (widget), "ico"));
3657 /* drop complete */
3659 gboolean
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))
3664 return FALSE;
3666 switch (context->action)
3668 case GDK_ACTION_MOVE:
3669 /* from userlist */
3670 mg_handle_drop (widget, y, &prefs.gui_ulist_pos, &prefs.tab_pos);
3671 break;
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);
3675 break;
3676 default:
3677 return FALSE;
3680 return TRUE;
3683 /* draw highlight rectangle in the destination */
3685 gboolean
3686 mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer scbar)
3688 GdkGC *gc;
3689 GdkColor col;
3690 GdkGCValues val;
3691 int half, width, height;
3692 int ox, oy;
3693 GtkPaned *paned;
3694 GdkDrawable *draw;
3696 /* ignore file drops */
3697 if (!mg_is_gui_target (context))
3698 return FALSE;
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;
3708 else
3710 ox = oy = 0;
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);
3726 half = height / 2;
3728 #if 0
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);
3736 return TRUE;
3738 #endif
3740 if (y < half)
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);
3746 else
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);
3755 return TRUE;