1 /* X-Chat
2  * Copyright (C) 1998-2007 Peter Zelezny.
3  *
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.
8  *
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.
13  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <string.h>
23 
24 #ifdef WIN32
25 #include <windows.h>
26 #include <io.h>
27 #else
28 #include <unistd.h>
29 #endif
30 
31 #include "fe-gtk.h"
32 
33 #include <gdk/gdkkeysyms.h>
34 
35 #include "../common/hexchat.h"
36 #include "../common/hexchatc.h"
37 #include "../common/cfgfiles.h"
38 #include "../common/outbound.h"
39 #include "../common/ignore.h"
40 #include "../common/fe.h"
41 #include "../common/server.h"
42 #include "../common/servlist.h"
43 #include "../common/notify.h"
44 #include "../common/util.h"
45 #include "../common/text.h"
46 #include "xtext.h"
47 #include "ascii.h"
48 #include "banlist.h"
49 #include "chanlist.h"
50 #include "editlist.h"
51 #include "fkeys.h"
52 #include "gtkutil.h"
53 #include "maingui.h"
54 #include "notifygui.h"
55 #include "pixmaps.h"
56 #include "rawlog.h"
57 #include "palette.h"
58 #include "plugingui.h"
59 #include "search.h"
60 #include "textgui.h"
61 #include "urlgrab.h"
62 #include "userlistgui.h"
63 #include "menu.h"
64 #include "servlistgui.h"
65 
66 static GSList *submenu_list;
67 
68 enum
69 {
70 	M_MENUITEM,
71 	M_NEWMENU,
72 	M_END,
73 	M_SEP,
74 	M_MENUTOG,
75 	M_MENURADIO,
76 	M_MENUSTOCK,
77 	M_MENUPIX,
78 	M_MENUSUB
79 };
80 
81 struct mymenu
82 {
83 	char *text;
84 	void *callback;
85 	char *image;
86 	unsigned char type;	/* M_XXX */
87 	unsigned char id;		/* MENU_ID_XXX (menu.h) */
88 	unsigned char state;	/* ticked or not? */
89 	unsigned char sensitive;	/* shaded out? */
90 	guint key;				/* GDK_KEY_x */
91 };
92 
93 #define XCMENU_DOLIST 1
94 #define XCMENU_SHADED 1
95 #define XCMENU_MARKUP 2
96 #define XCMENU_MNEMONIC 4
97 
98 /* execute a userlistbutton/popupmenu command */
99 
100 static void
nick_command(session * sess,char * cmd)101 nick_command (session * sess, char *cmd)
102 {
103 	if (*cmd == '!')
104 		hexchat_exec (cmd + 1);
105 	else
106 		handle_command (sess, cmd, TRUE);
107 }
108 
109 /* fill in the %a %s %n etc and execute the command */
110 
111 void
nick_command_parse(session * sess,char * cmd,char * nick,char * allnick)112 nick_command_parse (session *sess, char *cmd, char *nick, char *allnick)
113 {
114 	char *buf;
115 	char *host = _("Host unknown");
116 	char *account = _("Account unknown");
117 	struct User *user;
118 	int len;
119 
120 /*	if (sess->type == SESS_DIALOG)
121 	{
122 		buf = (char *)(GTK_ENTRY (sess->gui->topic_entry)->text);
123 		buf = strrchr (buf, '@');
124 		if (buf)
125 			host = buf + 1;
126 	} else*/
127 	{
128 		user = userlist_find (sess, nick);
129 		if (user)
130 		{
131 			if (user->hostname)
132 				host = strchr (user->hostname, '@') + 1;
133 			if (user->account)
134 				account = user->account;
135 		}
136 	}
137 
138 	/* this can't overflow, since popup->cmd is only 256 */
139 	len = strlen (cmd) + strlen (nick) + strlen (allnick) + 512;
140 	buf = g_malloc (len);
141 
142 	auto_insert (buf, len, cmd, 0, 0, allnick, sess->channel, "",
143 					 server_get_network (sess->server, TRUE), host,
144 					 sess->server->nick, nick, account);
145 
146 	nick_command (sess, buf);
147 
148 	g_free (buf);
149 }
150 
151 /* userlist button has been clicked */
152 
153 void
userlist_button_cb(GtkWidget * button,char * cmd)154 userlist_button_cb (GtkWidget * button, char *cmd)
155 {
156 	int i, num_sel, using_allnicks = FALSE;
157 	char **nicks, *allnicks;
158 	char *nick = NULL;
159 	session *sess;
160 
161 	sess = current_sess;
162 
163 	if (strstr (cmd, "%a"))
164 		using_allnicks = TRUE;
165 
166 	if (sess->type == SESS_DIALOG)
167 	{
168 		/* fake a selection */
169 		nicks = g_new (char *, 2);
170 		nicks[0] = g_strdup (sess->channel);
171 		nicks[1] = NULL;
172 		num_sel = 1;
173 	}
174 	else
175 	{
176 		/* find number of selected rows */
177 		nicks = userlist_selection_list (sess->gui->user_tree, &num_sel);
178 		if (num_sel < 1)
179 		{
180 			nick_command_parse (sess, cmd, "", "");
181 
182 			g_free (nicks);
183 			return;
184 		}
185 	}
186 
187 	/* create "allnicks" string */
188 	allnicks = g_malloc (((NICKLEN + 1) * num_sel) + 1);
189 	*allnicks = 0;
190 
191 	i = 0;
192 	while (nicks[i])
193 	{
194 		if (i > 0)
195 			strcat (allnicks, " ");
196 		strcat (allnicks, nicks[i]);
197 
198 		if (!nick)
199 			nick = nicks[0];
200 
201 		/* if not using "%a", execute the command once for each nickname */
202 		if (!using_allnicks)
203 			nick_command_parse (sess, cmd, nicks[i], "");
204 
205 		i++;
206 	}
207 
208 	if (using_allnicks)
209 	{
210 		if (!nick)
211 			nick = "";
212 		nick_command_parse (sess, cmd, nick, allnicks);
213 	}
214 
215 	while (num_sel)
216 	{
217 		num_sel--;
218 		g_free (nicks[num_sel]);
219 	}
220 
221 	g_free (nicks);
222 	g_free (allnicks);
223 }
224 
225 /* a popup-menu-item has been selected */
226 
227 static void
popup_menu_cb(GtkWidget * item,char * cmd)228 popup_menu_cb (GtkWidget * item, char *cmd)
229 {
230 	char *nick;
231 
232 	/* the userdata is set in menu_quick_item() */
233 	nick = g_object_get_data (G_OBJECT (item), "u");
234 
235 	if (!nick)	/* userlist popup menu */
236 	{
237 		/* treat it just like a userlist button */
238 		userlist_button_cb (NULL, cmd);
239 		return;
240 	}
241 
242 	if (!current_sess)	/* for url grabber window */
243 		nick_command_parse (sess_list->data, cmd, nick, nick);
244 	else
245 		nick_command_parse (current_sess, cmd, nick, nick);
246 }
247 
248 GtkWidget *
menu_toggle_item(char * label,GtkWidget * menu,void * callback,void * userdata,int state)249 menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata,
250 						int state)
251 {
252 	GtkWidget *item;
253 
254 	item = gtk_check_menu_item_new_with_mnemonic (label);
255 	gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state);
256 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
257 	g_signal_connect (G_OBJECT (item), "activate",
258 							G_CALLBACK (callback), userdata);
259 	gtk_widget_show (item);
260 
261 	return item;
262 }
263 
264 GtkWidget *
menu_quick_item(char * cmd,char * label,GtkWidget * menu,int flags,gpointer userdata,char * icon)265 menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags,
266 					  gpointer userdata, char *icon)
267 {
268 	GtkWidget *img, *item;
269 	char *path;
270 
271 	if (!label)
272 		item = gtk_menu_item_new ();
273 	else
274 	{
275 		if (icon)
276 		{
277 			/*if (flags & XCMENU_MARKUP)
278 				item = gtk_image_menu_item_new_with_markup (label);
279 			else*/
280 				item = gtk_image_menu_item_new_with_mnemonic (label);
281 			img = NULL;
282 			if (access (icon, R_OK) == 0)	/* try fullpath */
283 				img = gtk_image_new_from_file (icon);
284 			else
285 			{
286 				/* try relative to <xdir> */
287 				path = g_build_filename (get_xdir (), icon, NULL);
288 				if (access (path, R_OK) == 0)
289 					img = gtk_image_new_from_file (path);
290 				else
291 					img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU);
292 				g_free (path);
293 			}
294 
295 			if (img)
296 				gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img);
297 		}
298 		else
299 		{
300 			if (flags & XCMENU_MARKUP)
301 			{
302 				item = gtk_menu_item_new_with_label ("");
303 				if (flags & XCMENU_MNEMONIC)
304 					gtk_label_set_markup_with_mnemonic (GTK_LABEL (GTK_BIN (item)->child), label);
305 				else
306 					gtk_label_set_markup (GTK_LABEL (GTK_BIN (item)->child), label);
307 			} else
308 			{
309 				if (flags & XCMENU_MNEMONIC)
310 					item = gtk_menu_item_new_with_mnemonic (label);
311 				else
312 					item = gtk_menu_item_new_with_label (label);
313 			}
314 		}
315 	}
316 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
317 	g_object_set_data (G_OBJECT (item), "u", userdata);
318 	if (cmd)
319 		g_signal_connect (G_OBJECT (item), "activate",
320 								G_CALLBACK (popup_menu_cb), cmd);
321 	if (flags & XCMENU_SHADED)
322 		gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
323 	gtk_widget_show_all (item);
324 
325 	return item;
326 }
327 
328 static void
menu_quick_item_with_callback(void * callback,char * label,GtkWidget * menu,void * arg)329 menu_quick_item_with_callback (void *callback, char *label, GtkWidget * menu,
330 										 void *arg)
331 {
332 	GtkWidget *item;
333 
334 	item = gtk_menu_item_new_with_label (label);
335 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
336 	g_signal_connect (G_OBJECT (item), "activate",
337 							G_CALLBACK (callback), arg);
338 	gtk_widget_show (item);
339 }
340 
341 GtkWidget *
menu_quick_sub(char * name,GtkWidget * menu,GtkWidget ** sub_item_ret,int flags,int pos)342 menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags, int pos)
343 {
344 	GtkWidget *sub_menu;
345 	GtkWidget *sub_item;
346 
347 	if (!name)
348 		return menu;
349 
350 	/* Code to add a submenu */
351 	sub_menu = gtk_menu_new ();
352 	if (flags & XCMENU_MARKUP)
353 	{
354 		sub_item = gtk_menu_item_new_with_label ("");
355 		gtk_label_set_markup (GTK_LABEL (GTK_BIN (sub_item)->child), name);
356 	}
357 	else
358 	{
359 		if (flags & XCMENU_MNEMONIC)
360 			sub_item = gtk_menu_item_new_with_mnemonic (name);
361 		else
362 			sub_item = gtk_menu_item_new_with_label (name);
363 	}
364 	gtk_menu_shell_insert (GTK_MENU_SHELL (menu), sub_item, pos);
365 	gtk_widget_show (sub_item);
366 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub_item), sub_menu);
367 
368 	if (sub_item_ret)
369 		*sub_item_ret = sub_item;
370 
371 	if (flags & XCMENU_DOLIST)
372 		/* We create a new element in the list */
373 		submenu_list = g_slist_prepend (submenu_list, sub_menu);
374 	return sub_menu;
375 }
376 
377 static GtkWidget *
menu_quick_endsub(void)378 menu_quick_endsub (void)
379 {
380 	/* Just delete the first element in the linked list pointed to by first */
381 	if (submenu_list)
382 		submenu_list = g_slist_remove (submenu_list, submenu_list->data);
383 
384 	if (submenu_list)
385 		return (submenu_list->data);
386 	else
387 		return NULL;
388 }
389 
390 static void
toggle_cb(GtkWidget * item,char * pref_name)391 toggle_cb (GtkWidget *item, char *pref_name)
392 {
393 	char buf[256];
394 
395 	if (GTK_CHECK_MENU_ITEM (item)->active)
396 		g_snprintf (buf, sizeof (buf), "set %s 1", pref_name);
397 	else
398 		g_snprintf (buf, sizeof (buf), "set %s 0", pref_name);
399 
400 	handle_command (current_sess, buf, FALSE);
401 }
402 
403 static int
is_in_path(char * cmd)404 is_in_path (char *cmd)
405 {
406 	char *orig = g_strdup (cmd + 1);	/* 1st char is "!" */
407 	char *prog = orig;
408 	char **argv;
409 	int argc;
410 
411 	/* special-case these default entries. */
412 	/*                  123456789012345678 */
413 	if (strncmp (prog, "gnome-terminal -x ", 18) == 0)
414 	/* don't check for gnome-terminal, but the thing it's executing! */
415 		prog += 18;
416 
417 	if (g_shell_parse_argv (prog, &argc, &argv, NULL))
418 	{
419 		char *path = g_find_program_in_path (argv[0]);
420 		g_strfreev (argv);
421 		if (path)
422 		{
423 			g_free (path);
424 			g_free (orig);
425 			return 1;
426 		}
427 	}
428 
429 	g_free (orig);
430 	return 0;
431 }
432 
433 /* syntax: "LABEL~ICON~STUFF~ADDED~LATER~" */
434 
435 static void
menu_extract_icon(char * name,char ** label,char ** icon)436 menu_extract_icon (char *name, char **label, char **icon)
437 {
438 	char *p = name;
439 	char *start = NULL;
440 	char *end = NULL;
441 
442 	while (*p)
443 	{
444 		if (*p == '~')
445 		{
446 			/* escape \~ */
447 			if (p == name || p[-1] != '\\')
448 			{
449 				if (!start)
450 					start = p + 1;
451 				else if (!end)
452 					end = p + 1;
453 			}
454 		}
455 		p++;
456 	}
457 
458 	if (!end)
459 		end = p;
460 
461 	if (start && start != end)
462 	{
463 		*label = g_strndup (name, (start - name) - 1);
464 		*icon = g_strndup (start, (end - start) - 1);
465 	}
466 	else
467 	{
468 		*label = g_strdup (name);
469 		*icon = NULL;
470 	}
471 }
472 
473 /* append items to "menu" using the (struct popup*) list provided */
474 
475 void
menu_create(GtkWidget * menu,GSList * list,char * target,int check_path)476 menu_create (GtkWidget *menu, GSList *list, char *target, int check_path)
477 {
478 	struct popup *pop;
479 	GtkWidget *tempmenu = menu, *subitem = NULL;
480 	int childcount = 0;
481 
482 	submenu_list = g_slist_prepend (0, menu);
483 	while (list)
484 	{
485 		pop = (struct popup *) list->data;
486 
487 		if (!g_ascii_strncasecmp (pop->name, "SUB", 3))
488 		{
489 			childcount = 0;
490 			tempmenu = menu_quick_sub (pop->cmd, tempmenu, &subitem, XCMENU_DOLIST|XCMENU_MNEMONIC, -1);
491 
492 		} else if (!g_ascii_strncasecmp (pop->name, "TOGGLE", 6))
493 		{
494 			childcount++;
495 			menu_toggle_item (pop->name + 7, tempmenu, toggle_cb, pop->cmd,
496 									cfg_get_bool (pop->cmd));
497 
498 		} else if (!g_ascii_strncasecmp (pop->name, "ENDSUB", 6))
499 		{
500 			/* empty sub menu due to no programs in PATH? */
501 			if (check_path && childcount < 1)
502 				gtk_widget_destroy (subitem);
503 			subitem = NULL;
504 
505 			if (tempmenu != menu)
506 				tempmenu = menu_quick_endsub ();
507 			/* If we get here and tempmenu equals menu that means we havent got any submenus to exit from */
508 
509 		} else if (!g_ascii_strncasecmp (pop->name, "SEP", 3))
510 		{
511 			menu_quick_item (0, 0, tempmenu, XCMENU_SHADED, 0, 0);
512 
513 		} else
514 		{
515 			char *icon, *label;
516 
517 			/* default command in hexchat.c */
518 			if (pop->cmd[0] == 'n' && !strcmp (pop->cmd, "notify -n ASK %s"))
519 			{
520 				/* don't create this item if already in notify list */
521 				if (!target || notify_is_in_list (current_sess->server, target))
522 				{
523 					list = list->next;
524 					continue;
525 				}
526 			}
527 
528 			menu_extract_icon (pop->name, &label, &icon);
529 
530 			if (!check_path || pop->cmd[0] != '!')
531 			{
532 				menu_quick_item (pop->cmd, label, tempmenu, 0, target, icon);
533 			/* check if the program is in path, if not, leave it out! */
534 			} else if (is_in_path (pop->cmd))
535 			{
536 				childcount++;
537 				menu_quick_item (pop->cmd, label, tempmenu, 0, target, icon);
538 			}
539 
540 			g_free (label);
541 			g_free (icon);
542 		}
543 
544 		list = list->next;
545 	}
546 
547 	/* Let's clean up the linked list from mem */
548 	while (submenu_list)
549 		submenu_list = g_slist_remove (submenu_list, submenu_list->data);
550 }
551 
552 static char *str_copy = NULL;		/* for all pop-up menus */
553 static GtkWidget *nick_submenu = NULL;	/* user info submenu */
554 
555 static void
menu_destroy(GtkWidget * menu,gpointer objtounref)556 menu_destroy (GtkWidget *menu, gpointer objtounref)
557 {
558 	gtk_widget_destroy (menu);
559 	g_object_unref (menu);
560 	if (objtounref)
561 		g_object_unref (G_OBJECT (objtounref));
562 	nick_submenu = NULL;
563 }
564 
565 static void
menu_popup(GtkWidget * menu,GdkEventButton * event,gpointer objtounref)566 menu_popup (GtkWidget *menu, GdkEventButton *event, gpointer objtounref)
567 {
568 	if (event && event->window)
569 		gtk_menu_set_screen (GTK_MENU (menu), gdk_window_get_screen (event->window));
570 
571 	g_object_ref (menu);
572 	g_object_ref_sink (menu);
573 	g_object_unref (menu);
574 	g_signal_connect (G_OBJECT (menu), "selection-done",
575 							G_CALLBACK (menu_destroy), objtounref);
576 	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
577 						 0, event ? event->time : 0);
578 }
579 
580 static void
menu_nickinfo_cb(GtkWidget * menu,session * sess)581 menu_nickinfo_cb (GtkWidget *menu, session *sess)
582 {
583 	char buf[512];
584 
585 	if (!is_session (sess))
586 		return;
587 
588 	/* issue a /WHOIS */
589 	g_snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy);
590 	handle_command (sess, buf, FALSE);
591 	/* and hide the output */
592 	sess->server->skip_next_whois = 1;
593 }
594 
595 static void
copy_to_clipboard_cb(GtkWidget * item,char * url)596 copy_to_clipboard_cb (GtkWidget *item, char *url)
597 {
598 	gtkutil_copy_to_clipboard (item, NULL, url);
599 }
600 
601 /* returns boolean: Some data is missing */
602 
603 static gboolean
menu_create_nickinfo_menu(struct User * user,GtkWidget * submenu)604 menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
605 {
606 	char buf[512];
607 	char unknown[96];
608 	char *real, *fmt, *users_country;
609 	struct away_msg *away;
610 	gboolean missing = FALSE;
611 	GtkWidget *item;
612 
613 	/* let the translators tweak this if need be */
614 	fmt = _("<tt><b>%-11s</b></tt> %s");
615 	g_snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown"));
616 
617 	if (user->realname)
618 	{
619 		real = strip_color (user->realname, -1, STRIP_ALL|STRIP_ESCMARKUP);
620 		g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real);
621 		g_free (real);
622 	} else
623 	{
624 		g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown);
625 	}
626 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
627 	g_signal_connect (G_OBJECT (item), "activate",
628 							G_CALLBACK (copy_to_clipboard_cb),
629 							user->realname ? user->realname : unknown);
630 
631 	g_snprintf (buf, sizeof (buf), fmt, _("User:"),
632 				 user->hostname ? user->hostname : unknown);
633 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
634 	g_signal_connect (G_OBJECT (item), "activate",
635 							G_CALLBACK (copy_to_clipboard_cb),
636 							user->hostname ? user->hostname : unknown);
637 
638 	g_snprintf (buf, sizeof (buf), fmt, _("Account:"),
639 				 user->account ? user->account : unknown);
640 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
641 	g_signal_connect (G_OBJECT (item), "activate",
642 							G_CALLBACK (copy_to_clipboard_cb),
643 							user->account ? user->account : unknown);
644 
645 	users_country = country (user->hostname);
646 	if (users_country)
647 	{
648 		g_snprintf (buf, sizeof (buf), fmt, _ ("Country:"), users_country);
649 		item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
650 		g_signal_connect (G_OBJECT (item), "activate",
651 			G_CALLBACK (copy_to_clipboard_cb), users_country);
652 	}
653 
654 	g_snprintf (buf, sizeof (buf), fmt, _("Server:"),
655 				 user->servername ? user->servername : unknown);
656 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
657 	g_signal_connect (G_OBJECT (item), "activate",
658 							G_CALLBACK (copy_to_clipboard_cb),
659 							user->servername ? user->servername : unknown);
660 
661 	if (user->lasttalk)
662 	{
663 		char min[96];
664 
665 		g_snprintf (min, sizeof (min), _("%u minutes ago"),
666 					(unsigned int) ((time (0) - user->lasttalk) / 60));
667 		g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min);
668 	} else
669 	{
670 		g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown);
671 	}
672 	menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
673 
674 	if (user->away)
675 	{
676 		away = server_away_find_message (current_sess->server, user->nick);
677 		if (away)
678 		{
679 			char *msg = strip_color (away->message ? away->message : unknown, -1, STRIP_ALL|STRIP_ESCMARKUP);
680 			g_snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg);
681 			g_free (msg);
682 			item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
683 			g_signal_connect (G_OBJECT (item), "activate",
684 									G_CALLBACK (copy_to_clipboard_cb),
685 									away->message ? away->message : unknown);
686 		}
687 		else
688 			missing = TRUE;
689 	}
690 
691 	return missing;
692 }
693 
694 void
fe_userlist_update(session * sess,struct User * user)695 fe_userlist_update (session *sess, struct User *user)
696 {
697 	GList *items, *next;
698 
699 	if (!nick_submenu || !str_copy)
700 		return;
701 
702 	/* not the same nick as the menu? */
703 	if (sess->server->p_cmp (user->nick, str_copy))
704 		return;
705 
706 	/* get rid of the "show" signal */
707 	g_signal_handlers_disconnect_by_func (nick_submenu, menu_nickinfo_cb, sess);
708 
709 	/* destroy all the old items */
710 	items = ((GtkMenuShell *) nick_submenu)->children;
711 	while (items)
712 	{
713 		next = items->next;
714 		gtk_widget_destroy (items->data);
715 		items = next;
716 	}
717 
718 	/* and re-create them with new info */
719 	menu_create_nickinfo_menu (user, nick_submenu);
720 }
721 
722 void
menu_nickmenu(session * sess,GdkEventButton * event,char * nick,int num_sel)723 menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
724 {
725 	char buf[512];
726 	struct User *user;
727 	GtkWidget *submenu, *menu = gtk_menu_new ();
728 
729 	g_free (str_copy);
730 	str_copy = g_strdup (nick);
731 
732 	submenu_list = 0;	/* first time through, might not be 0 */
733 
734 	/* more than 1 nick selected? */
735 	if (num_sel > 1)
736 	{
737 		g_snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel);
738 		menu_quick_item (0, buf, menu, 0, 0, 0);
739 		menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);
740 	} else
741 	{
742 		user = userlist_find (sess, nick);	/* lasttalk is channel specific */
743 		if (!user)
744 			user = userlist_find_global (current_sess->server, nick);
745 		if (user)
746 		{
747 			nick_submenu = submenu = menu_quick_sub (nick, menu, NULL, XCMENU_DOLIST, -1);
748 
749 			if (menu_create_nickinfo_menu (user, submenu) ||
750 				 !user->hostname || !user->realname || !user->servername)
751 			{
752 				g_signal_connect (G_OBJECT (submenu), "show", G_CALLBACK (menu_nickinfo_cb), sess);
753 			}
754 
755 			menu_quick_endsub ();
756 			menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);
757 		}
758 	}
759 
760 	if (num_sel > 1)
761 		menu_create (menu, popup_list, NULL, FALSE);
762 	else
763 		menu_create (menu, popup_list, str_copy, FALSE);
764 
765 	if (num_sel == 0)	/* xtext click */
766 		menu_add_plugin_items (menu, "\x5$NICK", str_copy);
767 	else	/* userlist treeview click */
768 		menu_add_plugin_items (menu, "\x5$NICK", NULL);
769 
770 	menu_popup (menu, event, NULL);
771 }
772 
773 /* stuff for the View menu */
774 
775 static void
menu_showhide_cb(session * sess)776 menu_showhide_cb (session *sess)
777 {
778 	if (prefs.hex_gui_hide_menu)
779 		gtk_widget_hide (sess->gui->menu);
780 	else
781 		gtk_widget_show (sess->gui->menu);
782 }
783 
784 static void
menu_topic_showhide_cb(session * sess)785 menu_topic_showhide_cb (session *sess)
786 {
787 	if (prefs.hex_gui_topicbar)
788 		gtk_widget_show (sess->gui->topic_bar);
789 	else
790 		gtk_widget_hide (sess->gui->topic_bar);
791 }
792 
793 static void
menu_userlist_showhide_cb(session * sess)794 menu_userlist_showhide_cb (session *sess)
795 {
796 	mg_decide_userlist (sess, TRUE);
797 }
798 
799 static void
menu_ulbuttons_showhide_cb(session * sess)800 menu_ulbuttons_showhide_cb (session *sess)
801 {
802 	if (prefs.hex_gui_ulist_buttons)
803 		gtk_widget_show (sess->gui->button_box);
804 	else
805 		gtk_widget_hide (sess->gui->button_box);
806 }
807 
808 static void
menu_cmbuttons_showhide_cb(session * sess)809 menu_cmbuttons_showhide_cb (session *sess)
810 {
811 	switch (sess->type)
812 	{
813 	case SESS_CHANNEL:
814 		if (prefs.hex_gui_mode_buttons)
815 			gtk_widget_show (sess->gui->topicbutton_box);
816 		else
817 			gtk_widget_hide (sess->gui->topicbutton_box);
818 		break;
819 	default:
820 		gtk_widget_hide (sess->gui->topicbutton_box);
821 	}
822 }
823 
824 static void
menu_setting_foreach(void (* callback)(session *),int id,guint state)825 menu_setting_foreach (void (*callback) (session *), int id, guint state)
826 {
827 	session *sess;
828 	GSList *list;
829 	int maindone = FALSE;	/* do it only once for EVERY tab */
830 
831 	list = sess_list;
832 	while (list)
833 	{
834 		sess = list->data;
835 
836 		if (!sess->gui->is_tab || !maindone)
837 		{
838 			if (sess->gui->is_tab)
839 				maindone = TRUE;
840 			if (id != -1)
841 				GTK_CHECK_MENU_ITEM (sess->gui->menu_item[id])->active = state;
842 			if (callback)
843 				callback (sess);
844 		}
845 
846 		list = list->next;
847 	}
848 }
849 
850 void
menu_bar_toggle(void)851 menu_bar_toggle (void)
852 {
853 	prefs.hex_gui_hide_menu = !prefs.hex_gui_hide_menu;
854 	menu_setting_foreach (menu_showhide_cb, MENU_ID_MENUBAR, !prefs.hex_gui_hide_menu);
855 }
856 
857 static void
menu_bar_toggle_cb(void)858 menu_bar_toggle_cb (void)
859 {
860 	menu_bar_toggle ();
861 	if (prefs.hex_gui_hide_menu)
862 		fe_message (_("The Menubar is now hidden. You can show it again"
863 						  " by pressing Control+F9 or right-clicking in a blank part of"
864 						  " the main text area."), FE_MSG_INFO);
865 }
866 
867 static void
menu_topicbar_toggle(GtkWidget * wid,gpointer ud)868 menu_topicbar_toggle (GtkWidget *wid, gpointer ud)
869 {
870 	prefs.hex_gui_topicbar = !prefs.hex_gui_topicbar;
871 	menu_setting_foreach (menu_topic_showhide_cb, MENU_ID_TOPICBAR,
872 								 prefs.hex_gui_topicbar);
873 }
874 
875 static void
menu_userlist_toggle(GtkWidget * wid,gpointer ud)876 menu_userlist_toggle (GtkWidget *wid, gpointer ud)
877 {
878 	prefs.hex_gui_ulist_hide = !prefs.hex_gui_ulist_hide;
879 	menu_setting_foreach (menu_userlist_showhide_cb, MENU_ID_USERLIST,
880 								 !prefs.hex_gui_ulist_hide);
881 }
882 
883 static void
menu_ulbuttons_toggle(GtkWidget * wid,gpointer ud)884 menu_ulbuttons_toggle (GtkWidget *wid, gpointer ud)
885 {
886 	prefs.hex_gui_ulist_buttons = !prefs.hex_gui_ulist_buttons;
887 	menu_setting_foreach (menu_ulbuttons_showhide_cb, MENU_ID_ULBUTTONS,
888 								 prefs.hex_gui_ulist_buttons);
889 }
890 
891 static void
menu_cmbuttons_toggle(GtkWidget * wid,gpointer ud)892 menu_cmbuttons_toggle (GtkWidget *wid, gpointer ud)
893 {
894 	prefs.hex_gui_mode_buttons = !prefs.hex_gui_mode_buttons;
895 	menu_setting_foreach (menu_cmbuttons_showhide_cb, MENU_ID_MODEBUTTONS,
896 								 prefs.hex_gui_mode_buttons);
897 }
898 
899 static void
menu_fullscreen_toggle(GtkWidget * wid,gpointer ud)900 menu_fullscreen_toggle (GtkWidget *wid, gpointer ud)
901 {
902 	if (!prefs.hex_gui_win_fullscreen)
903 		gtk_window_fullscreen (GTK_WINDOW(parent_window));
904 	else
905 	{
906 		gtk_window_unfullscreen (GTK_WINDOW(parent_window));
907 
908 #ifdef WIN32
909 		if (!prefs.hex_gui_win_state) /* not maximized */
910 		{
911 			/* other window managers seem to handle this */
912 			gtk_window_resize (GTK_WINDOW (parent_window),
913 				prefs.hex_gui_win_width, prefs.hex_gui_win_height);
914 			gtk_window_move (GTK_WINDOW (parent_window),
915 				prefs.hex_gui_win_left, prefs.hex_gui_win_top);
916 		}
917 #endif
918 	}
919 }
920 
921 void
menu_middlemenu(session * sess,GdkEventButton * event)922 menu_middlemenu (session *sess, GdkEventButton *event)
923 {
924 	GtkWidget *menu;
925 	GtkAccelGroup *accel_group;
926 
927 	accel_group = gtk_accel_group_new ();
928 	menu = menu_create_main (accel_group, FALSE, sess->server->is_away, !sess->gui->is_tab, NULL);
929 	menu_popup (menu, event, accel_group);
930 }
931 
932 static void
open_url_cb(GtkWidget * item,char * url)933 open_url_cb (GtkWidget *item, char *url)
934 {
935 	char buf[512];
936 
937 	/* pass this to /URL so it can handle irc:// */
938 	g_snprintf (buf, sizeof (buf), "URL %s", url);
939 	handle_command (current_sess, buf, FALSE);
940 }
941 
942 void
menu_urlmenu(GdkEventButton * event,char * url)943 menu_urlmenu (GdkEventButton *event, char *url)
944 {
945 	GtkWidget *menu;
946 	char *tmp, *chop;
947 
948 	g_free (str_copy);
949 	str_copy = g_strdup (url);
950 
951 	menu = gtk_menu_new ();
952 	/* more than 51 chars? Chop it */
953 	if (g_utf8_strlen (str_copy, -1) >= 52)
954 	{
955 		tmp = g_strdup (str_copy);
956 		chop = g_utf8_offset_to_pointer (tmp, 48);
957 		chop[0] = chop[1] = chop[2] = '.';
958 		chop[3] = 0;
959 		menu_quick_item (0, tmp, menu, XCMENU_SHADED, 0, 0);
960 		g_free (tmp);
961 	} else
962 	{
963 		menu_quick_item (0, str_copy, menu, XCMENU_SHADED, 0, 0);
964 	}
965 	menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);
966 
967 	/* Two hardcoded entries */
968 	if (strncmp (str_copy, "irc://", 6) == 0 ||
969 	    strncmp (str_copy, "ircs://",7) == 0)
970 		menu_quick_item_with_callback (open_url_cb, _("Connect"), menu, str_copy);
971 	else
972 		menu_quick_item_with_callback (open_url_cb, _("Open Link in Browser"), menu, str_copy);
973 	menu_quick_item_with_callback (copy_to_clipboard_cb, _("Copy Selected Link"), menu, str_copy);
974 	/* custom ones from urlhandlers.conf */
975 	menu_create (menu, urlhandler_list, str_copy, TRUE);
976 	menu_add_plugin_items (menu, "\x4$URL", str_copy);
977 	menu_popup (menu, event, NULL);
978 }
979 
980 static void
menu_chan_cycle(GtkWidget * menu,char * chan)981 menu_chan_cycle (GtkWidget * menu, char *chan)
982 {
983 	char tbuf[256];
984 
985 	if (current_sess)
986 	{
987 		g_snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan);
988 		handle_command (current_sess, tbuf, FALSE);
989 	}
990 }
991 
992 static void
menu_chan_part(GtkWidget * menu,char * chan)993 menu_chan_part (GtkWidget * menu, char *chan)
994 {
995 	char tbuf[256];
996 
997 	if (current_sess)
998 	{
999 		g_snprintf (tbuf, sizeof tbuf, "part %s", chan);
1000 		handle_command (current_sess, tbuf, FALSE);
1001 	}
1002 }
1003 
1004 static void
menu_chan_focus(GtkWidget * menu,char * chan)1005 menu_chan_focus (GtkWidget * menu, char *chan)
1006 {
1007 	char tbuf[256];
1008 
1009 	if (current_sess)
1010 	{
1011 		g_snprintf (tbuf, sizeof tbuf, "doat %s gui focus", chan);
1012 		handle_command (current_sess, tbuf, FALSE);
1013 	}
1014 }
1015 
1016 static void
menu_chan_join(GtkWidget * menu,char * chan)1017 menu_chan_join (GtkWidget * menu, char *chan)
1018 {
1019 	char tbuf[256];
1020 
1021 	if (current_sess)
1022 	{
1023 		g_snprintf (tbuf, sizeof tbuf, "join %s", chan);
1024 		handle_command (current_sess, tbuf, FALSE);
1025 	}
1026 }
1027 
1028 void
menu_chanmenu(struct session * sess,GdkEventButton * event,char * chan)1029 menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan)
1030 {
1031 	GtkWidget *menu;
1032 	int is_joined = FALSE;
1033 	session * chan_session;
1034 
1035 	chan_session = find_channel (sess->server, chan);
1036 
1037 	if (chan_session)
1038 		is_joined = TRUE;
1039 
1040 	g_free (str_copy);
1041 	str_copy = g_strdup (chan);
1042 
1043 	menu = gtk_menu_new ();
1044 
1045 	menu_quick_item (0, chan, menu, XCMENU_SHADED, str_copy, 0);
1046 	menu_quick_item (0, 0, menu, XCMENU_SHADED, str_copy, 0);
1047 
1048 	if (!is_joined)
1049 		menu_quick_item_with_callback (menu_chan_join, _("Join Channel"), menu,
1050 												 str_copy);
1051 	else
1052 	{
1053 		if (chan_session != current_sess)
1054 			menu_quick_item_with_callback (menu_chan_focus, _("Focus Channel"), menu,
1055 													 str_copy);
1056 		menu_quick_item_with_callback (menu_chan_part, _("Part Channel"), menu,
1057 												 str_copy);
1058 		menu_quick_item_with_callback (menu_chan_cycle, _("Cycle Channel"), menu,
1059 												 str_copy);
1060 	}
1061 
1062 	menu_addfavoritemenu (sess->server, menu, str_copy, FALSE);
1063 
1064 	menu_add_plugin_items (menu, "\x5$CHAN", str_copy);
1065 	menu_popup (menu, event, NULL);
1066 }
1067 
1068 static void
menu_delfav_cb(GtkWidget * item,server * serv)1069 menu_delfav_cb (GtkWidget *item, server *serv)
1070 {
1071 	servlist_autojoinedit (serv->network, str_copy, FALSE);
1072 }
1073 
1074 static void
menu_addfav_cb(GtkWidget * item,server * serv)1075 menu_addfav_cb (GtkWidget *item, server *serv)
1076 {
1077 	servlist_autojoinedit (serv->network, str_copy, TRUE);
1078 }
1079 
1080 void
menu_addfavoritemenu(server * serv,GtkWidget * menu,char * channel,gboolean istree)1081 menu_addfavoritemenu (server *serv, GtkWidget *menu, char *channel, gboolean istree)
1082 {
1083 	char *str;
1084 
1085 	if (!serv->network)
1086 		return;
1087 
1088 	if (channel != str_copy)
1089 	{
1090 		g_free (str_copy);
1091 		str_copy = g_strdup (channel);
1092 	}
1093 
1094 	if (istree)
1095 		str = _("_Autojoin");
1096 	else
1097 		str = _("Autojoin Channel");
1098 
1099 	if (joinlist_is_in_list (serv, channel))
1100 	{
1101 		menu_toggle_item (str, menu, menu_delfav_cb, serv, TRUE);
1102 	}
1103 	else
1104 	{
1105 		menu_toggle_item (str, menu, menu_addfav_cb, serv, FALSE);
1106 	}
1107 }
1108 
1109 static void
menu_delautoconn_cb(GtkWidget * item,server * serv)1110 menu_delautoconn_cb (GtkWidget *item, server *serv)
1111 {
1112 	((ircnet*)serv->network)->flags &= ~FLAG_AUTO_CONNECT;
1113 	servlist_save ();
1114 }
1115 
1116 static void
menu_addautoconn_cb(GtkWidget * item,server * serv)1117 menu_addautoconn_cb (GtkWidget *item, server *serv)
1118 {
1119 	((ircnet*)serv->network)->flags |= FLAG_AUTO_CONNECT;
1120 	servlist_save ();
1121 }
1122 
1123 void
menu_addconnectmenu(server * serv,GtkWidget * menu)1124 menu_addconnectmenu (server *serv, GtkWidget *menu)
1125 {
1126 	if (!serv->network)
1127 		return;
1128 
1129 	if (((ircnet*)serv->network)->flags & FLAG_AUTO_CONNECT)
1130 	{
1131 		menu_toggle_item (_("_Auto-Connect"), menu, menu_delautoconn_cb, serv, TRUE);
1132 	}
1133 	else
1134 	{
1135 		menu_toggle_item (_("_Auto-Connect"), menu, menu_addautoconn_cb, serv, FALSE);
1136 	}
1137 }
1138 
1139 static void
menu_open_server_list(GtkWidget * wid,gpointer none)1140 menu_open_server_list (GtkWidget *wid, gpointer none)
1141 {
1142 	fe_serverlist_open (current_sess);
1143 }
1144 
1145 static void
menu_settings(GtkWidget * wid,gpointer none)1146 menu_settings (GtkWidget * wid, gpointer none)
1147 {
1148 	extern void setup_open (void);
1149 	setup_open ();
1150 }
1151 
1152 static void
menu_usermenu(void)1153 menu_usermenu (void)
1154 {
1155 	char buf[128];
1156 	g_snprintf(buf, sizeof(buf), _("User menu - %s"), _(DISPLAY_NAME));
1157 	editlist_gui_open (NULL, NULL, usermenu_list, buf, "usermenu", "usermenu.conf", 0);
1158 }
1159 
1160 static void
usermenu_create(GtkWidget * menu)1161 usermenu_create (GtkWidget *menu)
1162 {
1163 	menu_create (menu, usermenu_list, "", FALSE);
1164 	menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);	/* sep */
1165 	menu_quick_item_with_callback (menu_usermenu, _("Edit This Menu" ELLIPSIS), menu, 0);
1166 }
1167 
1168 static void
usermenu_destroy(GtkWidget * menu)1169 usermenu_destroy (GtkWidget * menu)
1170 {
1171 	GList *items = ((GtkMenuShell *) menu)->children;
1172 	GList *next;
1173 
1174 	while (items)
1175 	{
1176 		next = items->next;
1177 		gtk_widget_destroy (items->data);
1178 		items = next;
1179 	}
1180 }
1181 
1182 void
usermenu_update(void)1183 usermenu_update (void)
1184 {
1185 	int done_main = FALSE;
1186 	GSList *list = sess_list;
1187 	session *sess;
1188 	GtkWidget *menu;
1189 
1190 	while (list)
1191 	{
1192 		sess = list->data;
1193 		menu = sess->gui->menu_item[MENU_ID_USERMENU];
1194 		if (sess->gui->is_tab)
1195 		{
1196 			if (!done_main && menu)
1197 			{
1198 				usermenu_destroy (menu);
1199 				usermenu_create (menu);
1200 				done_main = TRUE;
1201 			}
1202 		} else if (menu)
1203 		{
1204 			usermenu_destroy (menu);
1205 			usermenu_create (menu);
1206 		}
1207 		list = list->next;
1208 	}
1209 }
1210 
1211 static void
menu_newserver_window(GtkWidget * wid,gpointer none)1212 menu_newserver_window (GtkWidget * wid, gpointer none)
1213 {
1214 	int old = prefs.hex_gui_tab_chans;
1215 
1216 	prefs.hex_gui_tab_chans = 0;
1217 	new_ircwindow (NULL, NULL, SESS_SERVER, 0);
1218 	prefs.hex_gui_tab_chans = old;
1219 }
1220 
1221 static void
menu_newchannel_window(GtkWidget * wid,gpointer none)1222 menu_newchannel_window (GtkWidget * wid, gpointer none)
1223 {
1224 	int old = prefs.hex_gui_tab_chans;
1225 
1226 	prefs.hex_gui_tab_chans = 0;
1227 	new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0);
1228 	prefs.hex_gui_tab_chans = old;
1229 }
1230 
1231 static void
menu_newserver_tab(GtkWidget * wid,gpointer none)1232 menu_newserver_tab (GtkWidget * wid, gpointer none)
1233 {
1234 	int old = prefs.hex_gui_tab_chans;
1235 	int oldf = prefs.hex_gui_tab_newtofront;
1236 
1237 	prefs.hex_gui_tab_chans = 1;
1238 	/* force focus if setting is "only requested tabs" */
1239 	if (prefs.hex_gui_tab_newtofront == 2)
1240 		prefs.hex_gui_tab_newtofront = 1;
1241 	new_ircwindow (NULL, NULL, SESS_SERVER, 0);
1242 	prefs.hex_gui_tab_chans = old;
1243 	prefs.hex_gui_tab_newtofront = oldf;
1244 }
1245 
1246 static void
menu_newchannel_tab(GtkWidget * wid,gpointer none)1247 menu_newchannel_tab (GtkWidget * wid, gpointer none)
1248 {
1249 	int old = prefs.hex_gui_tab_chans;
1250 
1251 	prefs.hex_gui_tab_chans = 1;
1252 	new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0);
1253 	prefs.hex_gui_tab_chans = old;
1254 }
1255 
1256 static void
menu_rawlog(GtkWidget * wid,gpointer none)1257 menu_rawlog (GtkWidget * wid, gpointer none)
1258 {
1259 	open_rawlog (current_sess->server);
1260 }
1261 
1262 static void
menu_detach(GtkWidget * wid,gpointer none)1263 menu_detach (GtkWidget * wid, gpointer none)
1264 {
1265 	mg_detach (current_sess, 0);
1266 }
1267 
1268 static void
menu_close(GtkWidget * wid,gpointer none)1269 menu_close (GtkWidget * wid, gpointer none)
1270 {
1271 	mg_close_sess (current_sess);
1272 }
1273 
1274 static void
menu_quit(GtkWidget * wid,gpointer none)1275 menu_quit (GtkWidget * wid, gpointer none)
1276 {
1277 	mg_open_quit_dialog (FALSE);
1278 }
1279 
1280 static void
menu_search(void)1281 menu_search (void)
1282 {
1283 	mg_search_toggle (current_sess);
1284 }
1285 
1286 static void
menu_search_next(GtkWidget * wid)1287 menu_search_next (GtkWidget *wid)
1288 {
1289 	mg_search_handle_next(wid, current_sess);
1290 }
1291 
1292 static void
menu_search_prev(GtkWidget * wid)1293 menu_search_prev (GtkWidget *wid)
1294 {
1295 	mg_search_handle_previous(wid, current_sess);
1296 }
1297 
1298 static void
menu_resetmarker(GtkWidget * wid,gpointer none)1299 menu_resetmarker (GtkWidget * wid, gpointer none)
1300 {
1301 	gtk_xtext_reset_marker_pos (GTK_XTEXT (current_sess->gui->xtext));
1302 }
1303 
1304 static void
menu_movetomarker(GtkWidget * wid,gpointer none)1305 menu_movetomarker (GtkWidget *wid, gpointer none)
1306 {
1307 	marker_reset_reason reason;
1308 	char *str;
1309 
1310 	if (!prefs.hex_text_show_marker)
1311 		PrintText (current_sess, _("Marker line disabled."));
1312 	else
1313 	{
1314 		reason = gtk_xtext_moveto_marker_pos (GTK_XTEXT (current_sess->gui->xtext));
1315 		switch (reason) {
1316 		case MARKER_WAS_NEVER_SET:
1317 			str = _("Marker line never set."); break;
1318 		case MARKER_IS_SET:
1319 			str = ""; break;
1320 		case MARKER_RESET_MANUALLY:
1321 			str = _("Marker line reset manually."); break;
1322 		case MARKER_RESET_BY_KILL:
1323 			str = _("Marker line reset because exceeded scrollback limit."); break;
1324 		case MARKER_RESET_BY_CLEAR:
1325 			str = _("Marker line reset by CLEAR command."); break;
1326 		default:
1327 			str = _("Marker line state unknown."); break;
1328 		}
1329 		if (str[0])
1330 			PrintText (current_sess, str);
1331 	}
1332 }
1333 
1334 static void
menu_copy_selection(GtkWidget * wid,gpointer none)1335 menu_copy_selection (GtkWidget * wid, gpointer none)
1336 {
1337 	gtk_xtext_copy_selection (GTK_XTEXT (current_sess->gui->xtext));
1338 }
1339 
1340 static void
menu_flushbuffer(GtkWidget * wid,gpointer none)1341 menu_flushbuffer (GtkWidget * wid, gpointer none)
1342 {
1343 	fe_text_clear (current_sess, 0);
1344 }
1345 
1346 static void
savebuffer_req_done(session * sess,char * file)1347 savebuffer_req_done (session *sess, char *file)
1348 {
1349 	int fh;
1350 
1351 	if (!file)
1352 		return;
1353 
1354 	fh = g_open (file, O_TRUNC | O_WRONLY | O_CREAT, 0600);
1355 	if (fh != -1)
1356 	{
1357 		gtk_xtext_save (GTK_XTEXT (sess->gui->xtext), fh);
1358 		close (fh);
1359 	}
1360 }
1361 
1362 static void
menu_savebuffer(GtkWidget * wid,gpointer none)1363 menu_savebuffer (GtkWidget * wid, gpointer none)
1364 {
1365 	gtkutil_file_req (_("Select an output filename"), savebuffer_req_done,
1366 							current_sess, NULL, NULL, FRF_WRITE);
1367 }
1368 
1369 static void
menu_disconnect(GtkWidget * wid,gpointer none)1370 menu_disconnect (GtkWidget * wid, gpointer none)
1371 {
1372 	handle_command (current_sess, "DISCON", FALSE);
1373 }
1374 
1375 static void
menu_reconnect(GtkWidget * wid,gpointer none)1376 menu_reconnect (GtkWidget * wid, gpointer none)
1377 {
1378 	if (current_sess->server->hostname[0])
1379 		handle_command (current_sess, "RECONNECT", FALSE);
1380 	else
1381 		fe_serverlist_open (current_sess);
1382 }
1383 
1384 static void
menu_join_cb(GtkWidget * dialog,gint response,GtkEntry * entry)1385 menu_join_cb (GtkWidget *dialog, gint response, GtkEntry *entry)
1386 {
1387 	switch (response)
1388 	{
1389 	case GTK_RESPONSE_ACCEPT:
1390 		menu_chan_join (NULL, entry->text);
1391 		break;
1392 
1393 	case GTK_RESPONSE_HELP:
1394 		chanlist_opengui (current_sess->server, TRUE);
1395 		break;
1396 	}
1397 
1398 	gtk_widget_destroy (dialog);
1399 }
1400 
1401 static void
menu_join_entry_cb(GtkWidget * entry,GtkDialog * dialog)1402 menu_join_entry_cb (GtkWidget *entry, GtkDialog *dialog)
1403 {
1404 	gtk_dialog_response (dialog, GTK_RESPONSE_ACCEPT);
1405 }
1406 
1407 static void
menu_join(GtkWidget * wid,gpointer none)1408 menu_join (GtkWidget * wid, gpointer none)
1409 {
1410 	GtkWidget *hbox, *dialog, *entry, *label;
1411 
1412 	dialog = gtk_dialog_new_with_buttons (_("Join Channel"),
1413 									GTK_WINDOW (parent_window), 0,
1414 									_("Retrieve channel list"), GTK_RESPONSE_HELP,
1415 									GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1416 									GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1417 									NULL);
1418 	gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dialog)->vbox), TRUE);
1419 	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1420 	hbox = gtk_hbox_new (TRUE, 0);
1421 
1422 	entry = gtk_entry_new ();
1423 	GTK_ENTRY (entry)->editable = 0;	/* avoid auto-selection */
1424 	gtk_entry_set_text (GTK_ENTRY (entry), "#");
1425 	g_signal_connect (G_OBJECT (entry), "activate",
1426 						 	G_CALLBACK (menu_join_entry_cb), dialog);
1427 	gtk_box_pack_end (GTK_BOX (hbox), entry, 0, 0, 0);
1428 
1429 	label = gtk_label_new (_("Enter Channel to Join:"));
1430 	gtk_box_pack_end (GTK_BOX (hbox), label, 0, 0, 0);
1431 
1432 	g_signal_connect (G_OBJECT (dialog), "response",
1433 						   G_CALLBACK (menu_join_cb), entry);
1434 
1435 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
1436 
1437 	gtk_widget_show_all (dialog);
1438 
1439 	gtk_editable_set_editable (GTK_EDITABLE (entry), TRUE);
1440 	gtk_editable_set_position (GTK_EDITABLE (entry), 1);
1441 }
1442 
1443 static void
menu_away(GtkCheckMenuItem * item,gpointer none)1444 menu_away (GtkCheckMenuItem *item, gpointer none)
1445 {
1446 	handle_command (current_sess, gtk_check_menu_item_get_active (item) ? "away" : "back", FALSE);
1447 }
1448 
1449 static void
menu_chanlist(GtkWidget * wid,gpointer none)1450 menu_chanlist (GtkWidget * wid, gpointer none)
1451 {
1452 	chanlist_opengui (current_sess->server, FALSE);
1453 }
1454 
1455 static void
menu_banlist(GtkWidget * wid,gpointer none)1456 menu_banlist (GtkWidget * wid, gpointer none)
1457 {
1458 	banlist_opengui (current_sess);
1459 }
1460 
1461 #ifdef USE_PLUGIN
1462 
1463 static void
menu_loadplugin(void)1464 menu_loadplugin (void)
1465 {
1466 	plugingui_load ();
1467 }
1468 
1469 static void
menu_pluginlist(void)1470 menu_pluginlist (void)
1471 {
1472 	plugingui_open ();
1473 }
1474 
1475 #else
1476 
1477 static void
menu_noplugin_info(void)1478 menu_noplugin_info (void)
1479 {
1480 	fe_message (_(DISPLAY_NAME " has been build without plugin support."), FE_MSG_INFO);
1481 }
1482 
1483 #define menu_loadplugin menu_noplugin_info
1484 #define menu_pluginlist menu_noplugin_info
1485 
1486 #endif
1487 
1488 #define usercommands_help  _("User Commands - Special codes:\n\n"\
1489                            "%c  =  current channel\n"\
1490 									"%e  =  current network name\n"\
1491 									"%m  =  machine info\n"\
1492                            "%n  =  your nick\n"\
1493 									"%t  =  time/date\n"\
1494                            "%v  =  HexChat version\n"\
1495                            "%2  =  word 2\n"\
1496                            "%3  =  word 3\n"\
1497                            "&2  =  word 2 to the end of line\n"\
1498                            "&3  =  word 3 to the end of line\n\n"\
1499                            "eg:\n"\
1500                            "/cmd john hello\n\n"\
1501                            "%2 would be \042john\042\n"\
1502                            "&2 would be \042john hello\042.")
1503 
1504 #define ulbutton_help       _("Userlist Buttons - Special codes:\n\n"\
1505 							"%a  =  all selected nicks\n"\
1506 							"%c  =  current channel\n"\
1507 							"%e  =  current network name\n"\
1508 							"%h  =  selected nick's hostname\n"\
1509 							"%m  =  machine info\n"\
1510 							"%n  =  your nick\n"\
1511 							"%s  =  selected nick\n"\
1512 							"%t  =  time/date\n"\
1513 							"%u  =  selected users account")
1514 
1515 #define dlgbutton_help      _("Dialog Buttons - Special codes:\n\n"\
1516 							"%a  =  all selected nicks\n"\
1517 							"%c  =  current channel\n"\
1518 							"%e  =  current network name\n"\
1519 							"%h  =  selected nick's hostname\n"\
1520 							"%m  =  machine info\n"\
1521 							"%n  =  your nick\n"\
1522 							"%s  =  selected nick\n"\
1523 							"%t  =  time/date\n"\
1524 							"%u  =  selected users account")
1525 
1526 #define ctcp_help          _("CTCP Replies - Special codes:\n\n"\
1527                            "%d  =  data (the whole ctcp)\n"\
1528 									"%e  =  current network name\n"\
1529 									"%m  =  machine info\n"\
1530                            "%s  =  nick who sent the ctcp\n"\
1531                            "%t  =  time/date\n"\
1532                            "%2  =  word 2\n"\
1533                            "%3  =  word 3\n"\
1534                            "&2  =  word 2 to the end of line\n"\
1535                            "&3  =  word 3 to the end of line\n\n")
1536 
1537 #define url_help           _("URL Handlers - Special codes:\n\n"\
1538                            "%s  =  the URL string\n\n"\
1539                            "Putting a ! in front of the command\n"\
1540                            "indicates it should be sent to a\n"\
1541                            "shell instead of HexChat")
1542 
1543 static void
menu_usercommands(void)1544 menu_usercommands (void)
1545 {
1546 	char buf[128];
1547 	g_snprintf(buf, sizeof(buf), _("User Defined Commands - %s"), _(DISPLAY_NAME));
1548 	editlist_gui_open (NULL, NULL, command_list, buf, "commands", "commands.conf",
1549 							usercommands_help);
1550 }
1551 
1552 static void
menu_ulpopup(void)1553 menu_ulpopup (void)
1554 {
1555 	char buf[128];
1556 	g_snprintf(buf, sizeof(buf), _("Userlist Popup menu -  %s"), _(DISPLAY_NAME));
1557 	editlist_gui_open (NULL, NULL, popup_list, buf, "popup", "popup.conf", ulbutton_help);
1558 }
1559 
1560 static void
menu_rpopup(void)1561 menu_rpopup (void)
1562 {
1563 	char buf[128];
1564 	g_snprintf(buf, sizeof(buf), _("Replace - %s"), _(DISPLAY_NAME));
1565 	editlist_gui_open (_("Text"), _("Replace with"), replace_list, buf, "replace", "replace.conf", 0);
1566 }
1567 
1568 static void
menu_urlhandlers(void)1569 menu_urlhandlers (void)
1570 {
1571 	char buf[128];
1572 	g_snprintf(buf, sizeof(buf), _("URL Handlers - %s"), _(DISPLAY_NAME));
1573 	editlist_gui_open (NULL, NULL, urlhandler_list, buf, "urlhandlers", "urlhandlers.conf", url_help);
1574 }
1575 
1576 static void
menu_evtpopup(void)1577 menu_evtpopup (void)
1578 {
1579 	pevent_dialog_show ();
1580 }
1581 
1582 static void
menu_keypopup(void)1583 menu_keypopup (void)
1584 {
1585 	key_dialog_show ();
1586 }
1587 
1588 static void
menu_ulbuttons(void)1589 menu_ulbuttons (void)
1590 {
1591 	char buf[128];
1592 	g_snprintf(buf, sizeof(buf), _("Userlist buttons - %s"), _(DISPLAY_NAME));
1593 	editlist_gui_open (NULL, NULL, button_list, buf, "buttons", "buttons.conf", ulbutton_help);
1594 }
1595 
1596 static void
menu_dlgbuttons(void)1597 menu_dlgbuttons (void)
1598 {
1599 	char buf[128];
1600 	g_snprintf(buf, sizeof(buf), _("Dialog buttons - %s"), _(DISPLAY_NAME));
1601 	editlist_gui_open (NULL, NULL, dlgbutton_list, buf, "dlgbuttons", "dlgbuttons.conf",
1602 							 dlgbutton_help);
1603 }
1604 
1605 static void
menu_ctcpguiopen(void)1606 menu_ctcpguiopen (void)
1607 {
1608 	char buf[128];
1609 	g_snprintf(buf, sizeof(buf), _("CTCP Replies - %s"), _(DISPLAY_NAME));
1610 	editlist_gui_open (NULL, NULL, ctcp_list, buf, "ctcpreply", "ctcpreply.conf", ctcp_help);
1611 }
1612 
1613 static void
menu_docs(GtkWidget * wid,gpointer none)1614 menu_docs (GtkWidget *wid, gpointer none)
1615 {
1616 	fe_open_url ("http://hexchat.readthedocs.org");
1617 }
1618 
1619 /*static void
1620 menu_webpage (GtkWidget *wid, gpointer none)
1621 {
1622 	fe_open_url ("http://xchat.org");
1623 }*/
1624 
1625 static void
menu_dcc_win(GtkWidget * wid,gpointer none)1626 menu_dcc_win (GtkWidget *wid, gpointer none)
1627 {
1628 	fe_dcc_open_recv_win (FALSE);
1629 	fe_dcc_open_send_win (FALSE);
1630 }
1631 
1632 static void
menu_dcc_chat_win(GtkWidget * wid,gpointer none)1633 menu_dcc_chat_win (GtkWidget *wid, gpointer none)
1634 {
1635 	fe_dcc_open_chat_win (FALSE);
1636 }
1637 
1638 void
menu_change_layout(void)1639 menu_change_layout (void)
1640 {
1641 	if (prefs.hex_gui_tab_layout == 0)
1642 	{
1643 		menu_setting_foreach (NULL, MENU_ID_LAYOUT_TABS, 1);
1644 		menu_setting_foreach (NULL, MENU_ID_LAYOUT_TREE, 0);
1645 		mg_change_layout (0);
1646 	} else
1647 	{
1648 		menu_setting_foreach (NULL, MENU_ID_LAYOUT_TABS, 0);
1649 		menu_setting_foreach (NULL, MENU_ID_LAYOUT_TREE, 1);
1650 		mg_change_layout (2);
1651 	}
1652 }
1653 
1654 static void
menu_layout_cb(GtkWidget * item,gpointer none)1655 menu_layout_cb (GtkWidget *item, gpointer none)
1656 {
1657 	prefs.hex_gui_tab_layout = 2;
1658 	if (GTK_CHECK_MENU_ITEM (item)->active)
1659 		prefs.hex_gui_tab_layout = 0;
1660 
1661 	menu_change_layout ();
1662 }
1663 
1664 static void
menu_apply_metres_cb(session * sess)1665 menu_apply_metres_cb (session *sess)
1666 {
1667 	mg_update_meters (sess->gui);
1668 }
1669 
1670 static void
menu_metres_off(GtkWidget * item,gpointer none)1671 menu_metres_off (GtkWidget *item, gpointer none)
1672 {
1673 	if (GTK_CHECK_MENU_ITEM (item)->active)
1674 	{
1675 		prefs.hex_gui_lagometer = 0;
1676 		prefs.hex_gui_throttlemeter = 0;
1677 		hexchat_reinit_timers ();
1678 		menu_setting_foreach (menu_apply_metres_cb, -1, 0);
1679 	}
1680 }
1681 
1682 static void
menu_metres_text(GtkWidget * item,gpointer none)1683 menu_metres_text (GtkWidget *item, gpointer none)
1684 {
1685 	if (GTK_CHECK_MENU_ITEM (item)->active)
1686 	{
1687 		prefs.hex_gui_lagometer = 2;
1688 		prefs.hex_gui_throttlemeter = 2;
1689 		hexchat_reinit_timers ();
1690 		menu_setting_foreach (menu_apply_metres_cb, -1, 0);
1691 	}
1692 }
1693 
1694 static void
menu_metres_graph(GtkWidget * item,gpointer none)1695 menu_metres_graph (GtkWidget *item, gpointer none)
1696 {
1697 	if (GTK_CHECK_MENU_ITEM (item)->active)
1698 	{
1699 		prefs.hex_gui_lagometer = 1;
1700 		prefs.hex_gui_throttlemeter = 1;
1701 		hexchat_reinit_timers ();
1702 		menu_setting_foreach (menu_apply_metres_cb, -1, 0);
1703 	}
1704 }
1705 
1706 static void
menu_metres_both(GtkWidget * item,gpointer none)1707 menu_metres_both (GtkWidget *item, gpointer none)
1708 {
1709 	if (GTK_CHECK_MENU_ITEM (item)->active)
1710 	{
1711 		prefs.hex_gui_lagometer = 3;
1712 		prefs.hex_gui_throttlemeter = 3;
1713 		hexchat_reinit_timers ();
1714 		menu_setting_foreach (menu_apply_metres_cb, -1, 0);
1715 	}
1716 }
1717 
1718 static void
about_dialog_close(GtkDialog * dialog,int response,gpointer data)1719 about_dialog_close (GtkDialog *dialog, int response, gpointer data)
1720 {
1721 	gtk_widget_destroy (GTK_WIDGET(dialog));
1722 }
1723 
1724 static gboolean
about_dialog_openurl(GtkAboutDialog * dialog,char * uri,gpointer data)1725 about_dialog_openurl (GtkAboutDialog *dialog, char *uri, gpointer data)
1726 {
1727 	fe_open_url (uri);
1728 	return TRUE;
1729 }
1730 
1731 static void
menu_about(GtkWidget * wid,gpointer sess)1732 menu_about (GtkWidget *wid, gpointer sess)
1733 {
1734 	GtkAboutDialog *dialog = GTK_ABOUT_DIALOG(gtk_about_dialog_new());
1735 	char comment[512];
1736 	char *license = "This program is free software; you can redistribute it and/or modify\n" \
1737 					"it under the terms of the GNU General Public License as published by\n" \
1738 					"the Free Software Foundation; version 2.\n\n" \
1739 					"This program is distributed in the hope that it will be useful,\n" \
1740 					"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
1741 					"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
1742 					"GNU General Public License for more details.\n\n" \
1743 					"You should have received a copy of the GNU General Public License\n" \
1744 					"along with this program. If not, see <http://www.gnu.org/licenses/>";
1745 
1746 	g_snprintf  (comment, sizeof(comment), ""
1747 #ifdef WIN32
1748 				"Portable Mode: %s\n"
1749 				"Build Type: x%d\n"
1750 #endif
1751 				"OS: %s",
1752 #ifdef WIN32
1753 				(portable_mode () ? "Yes" : "No"),
1754 				get_cpu_arch (),
1755 #endif
1756 				get_sys_str (0));
1757 
1758 	gtk_about_dialog_set_program_name (dialog, _(DISPLAY_NAME));
1759 	gtk_about_dialog_set_version (dialog, PACKAGE_VERSION);
1760 	gtk_about_dialog_set_license (dialog, license); /* gtk3 can use GTK_LICENSE_GPL_2_0 */
1761 	gtk_about_dialog_set_website (dialog, "http://hexchat.github.io");
1762 	gtk_about_dialog_set_website_label (dialog, "Website");
1763 	gtk_about_dialog_set_logo (dialog, pix_hexchat);
1764 	gtk_about_dialog_set_copyright (dialog, "\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2014 Berke Viktor");
1765 	gtk_about_dialog_set_comments (dialog, comment);
1766 
1767 	gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
1768 	g_signal_connect (G_OBJECT(dialog), "response", G_CALLBACK(about_dialog_close), NULL);
1769 	g_signal_connect (G_OBJECT(dialog), "activate-link", G_CALLBACK(about_dialog_openurl), NULL);
1770 
1771 	gtk_widget_show_all (GTK_WIDGET(dialog));
1772 }
1773 
1774 static struct mymenu mymenu[] = {
1775 	{N_("He_xChat"), 0, 0, M_NEWMENU, MENU_ID_HEXCHAT, 0, 1},
1776 	{N_("Network Li_st"), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_KEY_s},
1777 	{0, 0, 0, M_SEP, 0, 0, 0},
1778 
1779 	{N_("_New"), 0, GTK_STOCK_NEW, M_MENUSUB, 0, 0, 1},
1780 		{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_t},
1781 		{N_("Channel Tab"), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1},
1782 		{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_n},
1783 		{N_("Channel Window"), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1},
1784 		{0, 0, 0, M_END, 0, 0, 0},
1785 	{0, 0, 0, M_SEP, 0, 0, 0},
1786 
1787 	{N_("_Load Plugin or Script" ELLIPSIS), menu_loadplugin, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 1},
1788 	{0, 0, 0, M_SEP, 0, 0, 0},	/* 11 */
1789 #define DETACH_OFFSET (12)
1790 	{0, menu_detach, GTK_STOCK_REDO, M_MENUSTOCK, 0, 0, 1},	/* 12 */
1791 #define CLOSE_OFFSET (13)
1792 	{0, menu_close, GTK_STOCK_CLOSE, M_MENUSTOCK, 0, 0, 1},
1793 	{0, 0, 0, M_SEP, 0, 0, 0},
1794 	{N_("_Quit"), menu_quit, GTK_STOCK_QUIT, M_MENUSTOCK, 0, 0, 1, GDK_KEY_q},	/* 15 */
1795 
1796 	{N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1},
1797 #define MENUBAR_OFFSET (17)
1798 	{N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_KEY_F9},
1799 	{N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1},
1800 	{N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_KEY_F7},
1801 	{N_("U_ser List Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1},
1802 	{N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1},
1803 	{0, 0, 0, M_SEP, 0, 0, 0},
1804 	{N_("_Channel Switcher"), 0, 0, M_MENUSUB, 0, 0, 1},	/* 23 */
1805 #define TABS_OFFSET (24)
1806 		{N_("_Tabs"), menu_layout_cb, 0, M_MENURADIO, MENU_ID_LAYOUT_TABS, 0, 1},
1807 		{N_("T_ree"), 0, 0, M_MENURADIO, MENU_ID_LAYOUT_TREE, 0, 1},
1808 		{0, 0, 0, M_END, 0, 0, 0},
1809 	{N_("_Network Meters"), 0, 0, M_MENUSUB, 0, 0, 1},	/* 27 */
1810 #define METRE_OFFSET (28)
1811 		{N_("Off"), menu_metres_off, 0, M_MENURADIO, 0, 0, 1},
1812 		{N_("Graph"), menu_metres_graph, 0, M_MENURADIO, 0, 0, 1},
1813 		{N_("Text"), menu_metres_text, 0, M_MENURADIO, 0, 0, 1},
1814 		{N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1},
1815 		{0, 0, 0, M_END, 0, 0, 0},	/* 32 */
1816 	{ 0, 0, 0, M_SEP, 0, 0, 0 },
1817 	{N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1, GDK_KEY_F11},
1818 
1819 	{N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1},
1820 	{N_("_Disconnect"), menu_disconnect, GTK_STOCK_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1},
1821 	{N_("_Reconnect"), menu_reconnect, GTK_STOCK_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1},
1822 	{N_("_Join a Channel" ELLIPSIS), menu_join, GTK_STOCK_JUMP_TO, M_MENUSTOCK, MENU_ID_JOIN, 0, 1},
1823 	{N_("Channel _List"), menu_chanlist, GTK_STOCK_INDEX, M_MENUITEM, 0, 0, 1},
1824 	{0, 0, 0, M_SEP, 0, 0, 0},
1825 #define AWAY_OFFSET (41)
1826 	{N_("Marked _Away"), menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_KEY_a},
1827 
1828 	{N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1},	/* 40 */
1829 
1830 	{N_("S_ettings"), 0, 0, M_NEWMENU, 0, 0, 1},
1831 	{N_("_Preferences"), menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 0, 1},
1832 	{0, 0, 0, M_SEP, 0, 0, 0},
1833 	{N_("Auto Replace"), menu_rpopup, 0, M_MENUITEM, 0, 0, 1},
1834 	{N_("CTCP Replies"), menu_ctcpguiopen, 0, M_MENUITEM, 0, 0, 1},
1835 	{N_("Dialog Buttons"), menu_dlgbuttons, 0, M_MENUITEM, 0, 0, 1},
1836 	{N_("Keyboard Shortcuts"), menu_keypopup, 0, M_MENUITEM, 0, 0, 1},
1837 	{N_("Text Events"), menu_evtpopup, 0, M_MENUITEM, 0, 0, 1},
1838 	{N_("URL Handlers"), menu_urlhandlers, 0, M_MENUITEM, 0, 0, 1},
1839 	{N_("User Commands"), menu_usercommands, 0, M_MENUITEM, 0, 0, 1},
1840 	{N_("User List Buttons"), menu_ulbuttons, 0, M_MENUITEM, 0, 0, 1},
1841 	{N_("User List Popup"), menu_ulpopup, 0, M_MENUITEM, 0, 0, 1},	/* 52 */
1842 
1843 	{N_("_Window"), 0, 0, M_NEWMENU, 0, 0, 1},
1844 	{N_("_Ban List"), menu_banlist, 0, M_MENUITEM, 0, 0, 1},
1845 	{N_("Character Chart"), ascii_open, 0, M_MENUITEM, 0, 0, 1},
1846 	{N_("Direct Chat"), menu_dcc_chat_win, 0, M_MENUITEM, 0, 0, 1},
1847 	{N_("File _Transfers"), menu_dcc_win, 0, M_MENUITEM, 0, 0, 1},
1848 	{N_("Friends List"), notify_opengui, 0, M_MENUITEM, 0, 0, 1},
1849 	{N_("Ignore List"), ignore_gui_open, 0, M_MENUITEM, 0, 0, 1},
1850 	{N_("_Plugins and Scripts"), menu_pluginlist, 0, M_MENUITEM, 0, 0, 1},
1851 	{N_("_Raw Log"), menu_rawlog, 0, M_MENUITEM, 0, 0, 1},	/* 61 */
1852 	{N_("_URL Grabber"), url_opengui, 0, M_MENUITEM, 0, 0, 1},
1853 	{0, 0, 0, M_SEP, 0, 0, 0},
1854 	{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m},
1855 	{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M},
1856 	{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C},
1857 	{N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1},
1858 	{N_("Save Text" ELLIPSIS), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1},
1859 #define SEARCH_OFFSET (70)
1860 	{N_("Search"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1},
1861 		{N_("Search Text" ELLIPSIS), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_f},
1862 		{N_("Search Next"   ), menu_search_next, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_g},
1863 		{N_("Search Previous"   ), menu_search_prev, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_G},
1864 		{0, 0, 0, M_END, 0, 0, 0},
1865 
1866 	{N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1},	/* 74 */
1867 	{N_("_Contents"), menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 0, 1, GDK_KEY_F1},
1868 	{N_("_About"), menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 0, 1},
1869 
1870 	{0, 0, 0, M_END, 0, 0, 0},
1871 };
1872 
1873 void
menu_set_away(session_gui * gui,int away)1874 menu_set_away (session_gui *gui, int away)
1875 {
1876 	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (gui->menu_item[MENU_ID_AWAY]);
1877 
1878 	g_signal_handlers_block_by_func (G_OBJECT (item), menu_away, NULL);
1879 	gtk_check_menu_item_set_active (item, away);
1880 	g_signal_handlers_unblock_by_func (G_OBJECT (item), menu_away, NULL);
1881 }
1882 
1883 void
menu_set_fullscreen(session_gui * gui,int full)1884 menu_set_fullscreen (session_gui *gui, int full)
1885 {
1886 	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (gui->menu_item[MENU_ID_FULLSCREEN]);
1887 
1888 	g_signal_handlers_block_by_func (G_OBJECT (item), menu_fullscreen_toggle, NULL);
1889 	gtk_check_menu_item_set_active (item, full);
1890 	g_signal_handlers_unblock_by_func (G_OBJECT (item), menu_fullscreen_toggle, NULL);
1891 }
1892 
1893 GtkWidget *
create_icon_menu(char * labeltext,void * stock_name,int is_stock)1894 create_icon_menu (char *labeltext, void *stock_name, int is_stock)
1895 {
1896 	GtkWidget *item, *img;
1897 
1898 	if (is_stock)
1899 		img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU);
1900 	else
1901 		img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name));
1902 	item = gtk_image_menu_item_new_with_mnemonic (labeltext);
1903 	gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img);
1904 	gtk_widget_show (img);
1905 
1906 	return item;
1907 }
1908 
1909 /* Override the default GTK2.4 handler, which would make menu
1910    bindings not work when the menu-bar is hidden. */
1911 static gboolean
menu_canacaccel(GtkWidget * widget,guint signal_id,gpointer user_data)1912 menu_canacaccel (GtkWidget *widget, guint signal_id, gpointer user_data)
1913 {
1914 	/* GTK2.2 behaviour */
1915 	return gtk_widget_is_sensitive (widget);
1916 }
1917 
1918 /* === STUFF FOR /MENU === */
1919 
1920 static GtkMenuItem *
menu_find_item(GtkWidget * menu,char * name)1921 menu_find_item (GtkWidget *menu, char *name)
1922 {
1923 	GList *items = ((GtkMenuShell *) menu)->children;
1924 	GtkMenuItem *item;
1925 	GtkWidget *child;
1926 	const char *labeltext;
1927 
1928 	while (items)
1929 	{
1930 		item = items->data;
1931 		child = GTK_BIN (item)->child;
1932 		if (child)	/* separators arn't labels, skip them */
1933 		{
1934 			labeltext = g_object_get_data (G_OBJECT (item), "name");
1935 			if (!labeltext)
1936 				labeltext = gtk_label_get_text (GTK_LABEL (child));
1937 			if (!menu_streq (labeltext, name, 1))
1938 				return item;
1939 		} else if (name == NULL)
1940 		{
1941 			return item;
1942 		}
1943 		items = items->next;
1944 	}
1945 
1946 	return NULL;
1947 }
1948 
1949 static GtkWidget *
menu_find_path(GtkWidget * menu,char * path)1950 menu_find_path (GtkWidget *menu, char *path)
1951 {
1952 	GtkMenuItem *item;
1953 	char *s;
1954 	char name[128];
1955 	int len;
1956 
1957 	/* grab the next part of the path */
1958 	s = strchr (path, '/');
1959 	len = s - path;
1960 	if (!s)
1961 		len = strlen (path);
1962 	len = MIN (len, sizeof (name) - 1);
1963 	memcpy (name, path, len);
1964 	name[len] = 0;
1965 
1966 	item = menu_find_item (menu, name);
1967 	if (!item)
1968 		return NULL;
1969 
1970 	menu = gtk_menu_item_get_submenu (item);
1971 	if (!menu)
1972 		return NULL;
1973 
1974 	path += len;
1975 	if (*path == 0)
1976 		return menu;
1977 
1978 	return menu_find_path (menu, path + 1);
1979 }
1980 
1981 static GtkWidget *
menu_find(GtkWidget * menu,char * path,char * label)1982 menu_find (GtkWidget *menu, char *path, char *label)
1983 {
1984 	GtkWidget *item = NULL;
1985 
1986 	if (path[0] != 0)
1987 		menu = menu_find_path (menu, path);
1988 	if (menu)
1989 		item = (GtkWidget *)menu_find_item (menu, label);
1990 	return item;
1991 }
1992 
1993 static void
menu_foreach_gui(menu_entry * me,void (* callback)(GtkWidget *,menu_entry *,char *))1994 menu_foreach_gui (menu_entry *me, void (*callback) (GtkWidget *, menu_entry *, char *))
1995 {
1996 	GSList *list = sess_list;
1997 	int tabdone = FALSE;
1998 	session *sess;
1999 
2000 	if (!me->is_main)
2001 		return;	/* not main menu */
2002 
2003 	while (list)
2004 	{
2005 		sess = list->data;
2006 		/* do it only once for tab sessions, since they share a GUI */
2007 		if (!sess->gui->is_tab || !tabdone)
2008 		{
2009 			callback (sess->gui->menu, me, NULL);
2010 			if (sess->gui->is_tab)
2011 				tabdone = TRUE;
2012 		}
2013 		list = list->next;
2014 	}
2015 }
2016 
2017 static void
menu_update_cb(GtkWidget * menu,menu_entry * me,char * target)2018 menu_update_cb (GtkWidget *menu, menu_entry *me, char *target)
2019 {
2020 	GtkWidget *item;
2021 
2022 	item = menu_find (menu, me->path, me->label);
2023 	if (item)
2024 	{
2025 		gtk_widget_set_sensitive (item, me->enable);
2026 		/* must do it without triggering the callback */
2027 		if (GTK_IS_CHECK_MENU_ITEM (item))
2028 			GTK_CHECK_MENU_ITEM (item)->active = me->state;
2029 	}
2030 }
2031 
2032 /* radio state changed via mouse click */
2033 static void
menu_radio_cb(GtkCheckMenuItem * item,menu_entry * me)2034 menu_radio_cb (GtkCheckMenuItem *item, menu_entry *me)
2035 {
2036 	me->state = 0;
2037 	if (item->active)
2038 		me->state = 1;
2039 
2040 	/* update the state, incase this was changed via right-click. */
2041 	/* This will update all other windows and menu bars */
2042 	menu_foreach_gui (me, menu_update_cb);
2043 
2044 	if (me->state && me->cmd)
2045 		handle_command (current_sess, me->cmd, FALSE);
2046 }
2047 
2048 /* toggle state changed via mouse click */
2049 static void
menu_toggle_cb(GtkCheckMenuItem * item,menu_entry * me)2050 menu_toggle_cb (GtkCheckMenuItem *item, menu_entry *me)
2051 {
2052 	me->state = 0;
2053 	if (item->active)
2054 		me->state = 1;
2055 
2056 	/* update the state, incase this was changed via right-click. */
2057 	/* This will update all other windows and menu bars */
2058 	menu_foreach_gui (me, menu_update_cb);
2059 
2060 	if (me->state)
2061 		handle_command (current_sess, me->cmd, FALSE);
2062 	else
2063 		handle_command (current_sess, me->ucmd, FALSE);
2064 }
2065 
2066 static GtkWidget *
menu_radio_item(char * label,GtkWidget * menu,void * callback,void * userdata,int state,char * groupname)2067 menu_radio_item (char *label, GtkWidget *menu, void *callback, void *userdata,
2068 						int state, char *groupname)
2069 {
2070 	GtkWidget *item;
2071 	GtkMenuItem *parent;
2072 	GSList *grouplist = NULL;
2073 
2074 	parent = menu_find_item (menu, groupname);
2075 	if (parent)
2076 		grouplist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem *)parent);
2077 
2078 	item = gtk_radio_menu_item_new_with_label (grouplist, label);
2079 	gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state);
2080 	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2081 	g_signal_connect (G_OBJECT (item), "activate",
2082 							G_CALLBACK (callback), userdata);
2083 	gtk_widget_show (item);
2084 
2085 	return item;
2086 }
2087 
2088 static void
menu_reorder(GtkMenu * menu,GtkWidget * item,int pos)2089 menu_reorder (GtkMenu *menu, GtkWidget *item, int pos)
2090 {
2091 	if (pos == 0xffff)	/* outbound.c uses this default */
2092 		return;
2093 
2094 	if (pos < 0)	/* position offset from end/bottom */
2095 		gtk_menu_reorder_child (menu, item, (g_list_length (GTK_MENU_SHELL (menu)->children) + pos) - 1);
2096 	else
2097 		gtk_menu_reorder_child (menu, item, pos);
2098 }
2099 
2100 static GtkWidget *
menu_add_radio(GtkWidget * menu,menu_entry * me)2101 menu_add_radio (GtkWidget *menu, menu_entry *me)
2102 {
2103 	GtkWidget *item = NULL;
2104 	char *path = me->path + me->root_offset;
2105 
2106 	if (path[0] != 0)
2107 		menu = menu_find_path (menu, path);
2108 	if (menu)
2109 	{
2110 		item = menu_radio_item (me->label, menu, menu_radio_cb, me, me->state, me->group);
2111 		menu_reorder (GTK_MENU (menu), item, me->pos);
2112 	}
2113 	return item;
2114 }
2115 
2116 static GtkWidget *
menu_add_toggle(GtkWidget * menu,menu_entry * me)2117 menu_add_toggle (GtkWidget *menu, menu_entry *me)
2118 {
2119 	GtkWidget *item = NULL;
2120 	char *path = me->path + me->root_offset;
2121 
2122 	if (path[0] != 0)
2123 		menu = menu_find_path (menu, path);
2124 	if (menu)
2125 	{
2126 		item = menu_toggle_item (me->label, menu, menu_toggle_cb, me, me->state);
2127 		menu_reorder (GTK_MENU (menu), item, me->pos);
2128 	}
2129 	return item;
2130 }
2131 
2132 static GtkWidget *
menu_add_item(GtkWidget * menu,menu_entry * me,char * target)2133 menu_add_item (GtkWidget *menu, menu_entry *me, char *target)
2134 {
2135 	GtkWidget *item = NULL;
2136 	char *path = me->path + me->root_offset;
2137 
2138 	if (path[0] != 0)
2139 		menu = menu_find_path (menu, path);
2140 	if (menu)
2141 	{
2142 		item = menu_quick_item (me->cmd, me->label, menu, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, target, me->icon);
2143 		menu_reorder (GTK_MENU (menu), item, me->pos);
2144 	}
2145 	return item;
2146 }
2147 
2148 static GtkWidget *
menu_add_sub(GtkWidget * menu,menu_entry * me)2149 menu_add_sub (GtkWidget *menu, menu_entry *me)
2150 {
2151 	GtkWidget *item = NULL;
2152 	char *path = me->path + me->root_offset;
2153 	int pos;
2154 
2155 	if (path[0] != 0)
2156 		menu = menu_find_path (menu, path);
2157 	if (menu)
2158 	{
2159 		pos = me->pos;
2160 		if (pos < 0)	/* position offset from end/bottom */
2161 			pos = g_list_length (GTK_MENU_SHELL (menu)->children) + pos;
2162 		menu_quick_sub (me->label, menu, &item, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, pos);
2163 	}
2164 	return item;
2165 }
2166 
2167 static void
menu_del_cb(GtkWidget * menu,menu_entry * me,char * target)2168 menu_del_cb (GtkWidget *menu, menu_entry *me, char *target)
2169 {
2170 	GtkWidget *item = menu_find (menu, me->path + me->root_offset, me->label);
2171 	if (item)
2172 		gtk_widget_destroy (item);
2173 }
2174 
2175 static void
menu_add_cb(GtkWidget * menu,menu_entry * me,char * target)2176 menu_add_cb (GtkWidget *menu, menu_entry *me, char *target)
2177 {
2178 	GtkWidget *item;
2179 	GtkAccelGroup *accel_group;
2180 
2181 	if (me->group)	/* have a group name? Must be a radio item */
2182 		item = menu_add_radio (menu, me);
2183 	else if (me->ucmd)	/* have unselect-cmd? Must be a toggle item */
2184 		item = menu_add_toggle (menu, me);
2185 	else if (me->cmd || !me->label)	/* label=NULL for separators */
2186 		item = menu_add_item (menu, me, target);
2187 	else
2188 		item = menu_add_sub (menu, me);
2189 
2190 	if (item)
2191 	{
2192 		gtk_widget_set_sensitive (item, me->enable);
2193 		if (me->key)
2194 		{
2195 			accel_group = g_object_get_data (G_OBJECT (menu), "accel");
2196 			if (accel_group)	/* popup menus don't have them */
2197 				gtk_widget_add_accelerator (item, "activate", accel_group, me->key,
2198 													 me->modifier, GTK_ACCEL_VISIBLE);
2199 		}
2200 	}
2201 }
2202 
2203 char *
fe_menu_add(menu_entry * me)2204 fe_menu_add (menu_entry *me)
2205 {
2206 	char *text;
2207 
2208 	menu_foreach_gui (me, menu_add_cb);
2209 
2210 	if (!me->markup)
2211 		return NULL;
2212 
2213 	if (!pango_parse_markup (me->label, -1, 0, NULL, &text, NULL, NULL))
2214 		return NULL;
2215 
2216 	/* return the label with markup stripped */
2217 	return text;
2218 }
2219 
2220 void
fe_menu_del(menu_entry * me)2221 fe_menu_del (menu_entry *me)
2222 {
2223 	menu_foreach_gui (me, menu_del_cb);
2224 }
2225 
2226 void
fe_menu_update(menu_entry * me)2227 fe_menu_update (menu_entry *me)
2228 {
2229 	menu_foreach_gui (me, menu_update_cb);
2230 }
2231 
2232 /* used to add custom menus to the right-click menu */
2233 
2234 static void
menu_add_plugin_mainmenu_items(GtkWidget * menu)2235 menu_add_plugin_mainmenu_items (GtkWidget *menu)
2236 {
2237 	GSList *list;
2238 	menu_entry *me;
2239 
2240 	list = menu_list;	/* outbound.c */
2241 	while (list)
2242 	{
2243 		me = list->data;
2244 		if (me->is_main)
2245 			menu_add_cb (menu, me, NULL);
2246 		list = list->next;
2247 	}
2248 }
2249 
2250 void
menu_add_plugin_items(GtkWidget * menu,char * root,char * target)2251 menu_add_plugin_items (GtkWidget *menu, char *root, char *target)
2252 {
2253 	GSList *list;
2254 	menu_entry *me;
2255 
2256 	list = menu_list;	/* outbound.c */
2257 	while (list)
2258 	{
2259 		me = list->data;
2260 		if (!me->is_main && !strncmp (me->path, root + 1, root[0]))
2261 			menu_add_cb (menu, me, target);
2262 		list = list->next;
2263 	}
2264 }
2265 
2266 /* === END STUFF FOR /MENU === */
2267 
2268 GtkWidget *
menu_create_main(void * accel_group,int bar,int away,int toplevel,GtkWidget ** menu_widgets)2269 menu_create_main (void *accel_group, int bar, int away, int toplevel,
2270 						GtkWidget **menu_widgets)
2271 {
2272 	int i = 0;
2273 	GtkWidget *item;
2274 	GtkWidget *menu = 0;
2275 	GtkWidget *menu_item = 0;
2276 	GtkWidget *menu_bar;
2277 	GtkWidget *usermenu = 0;
2278 	GtkWidget *submenu = 0;
2279 	int close_mask = STATE_CTRL;
2280 	int away_mask = STATE_ALT;
2281 	char *key_theme = NULL;
2282 	GtkSettings *settings;
2283 	GSList *group = NULL;
2284 #ifdef HAVE_GTK_MAC
2285 	int appmenu_offset = 1; /* 0 is for about */
2286 #endif
2287 
2288 	if (bar)
2289 	{
2290 		menu_bar = gtk_menu_bar_new ();
2291 #ifdef HAVE_GTK_MAC
2292 		gtkosx_application_set_menu_bar (osx_app, GTK_MENU_SHELL (menu_bar));
2293 #endif
2294 	}
2295 	else
2296 		menu_bar = gtk_menu_new ();
2297 
2298 	/* /MENU needs to know this later */
2299 	g_object_set_data (G_OBJECT (menu_bar), "accel", accel_group);
2300 
2301 	g_signal_connect (G_OBJECT (menu_bar), "can-activate-accel",
2302 							G_CALLBACK (menu_canacaccel), 0);
2303 
2304 	/* set the initial state of toggles */
2305 	mymenu[MENUBAR_OFFSET].state = !prefs.hex_gui_hide_menu;
2306 	mymenu[MENUBAR_OFFSET+1].state = prefs.hex_gui_topicbar;
2307 	mymenu[MENUBAR_OFFSET+2].state = !prefs.hex_gui_ulist_hide;
2308 	mymenu[MENUBAR_OFFSET+3].state = prefs.hex_gui_ulist_buttons;
2309 	mymenu[MENUBAR_OFFSET+4].state = prefs.hex_gui_mode_buttons;
2310 
2311 	mymenu[AWAY_OFFSET].state = away;
2312 
2313 	switch (prefs.hex_gui_tab_layout)
2314 	{
2315 	case 0:
2316 		mymenu[TABS_OFFSET].state = 1;
2317 		mymenu[TABS_OFFSET+1].state = 0;
2318 		break;
2319 	default:
2320 		mymenu[TABS_OFFSET].state = 0;
2321 		mymenu[TABS_OFFSET+1].state = 1;
2322 	}
2323 
2324 	mymenu[METRE_OFFSET].state = 0;
2325 	mymenu[METRE_OFFSET+1].state = 0;
2326 	mymenu[METRE_OFFSET+2].state = 0;
2327 	mymenu[METRE_OFFSET+3].state = 0;
2328 	switch (prefs.hex_gui_lagometer)
2329 	{
2330 	case 0:
2331 		mymenu[METRE_OFFSET].state = 1;
2332 		break;
2333 	case 1:
2334 		mymenu[METRE_OFFSET+1].state = 1;
2335 		break;
2336 	case 2:
2337 		mymenu[METRE_OFFSET+2].state = 1;
2338 		break;
2339 	default:
2340 		mymenu[METRE_OFFSET+3].state = 1;
2341 	}
2342 
2343 	/* change Close binding to ctrl-shift-w when using emacs keys */
2344 	settings = gtk_widget_get_settings (menu_bar);
2345 	if (settings)
2346 	{
2347 		g_object_get (settings, "gtk-key-theme-name", &key_theme, NULL);
2348 		if (key_theme)
2349 		{
2350 			if (!g_ascii_strcasecmp (key_theme, "Emacs"))
2351 			{
2352 				close_mask = STATE_SHIFT | STATE_CTRL;
2353 				mymenu[SEARCH_OFFSET].key = 0;
2354 			}
2355 			g_free (key_theme);
2356 		}
2357 	}
2358 
2359 	/* Away binding to ctrl-alt-a if the _Help menu conflicts (FR/PT/IT) */
2360 	{
2361 		char *help = _("_Help");
2362 		char *under = strchr (help, '_');
2363 		if (under && (under[1] == 'a' || under[1] == 'A'))
2364 			away_mask = STATE_ALT | STATE_CTRL;
2365 	}
2366 
2367 	if (!toplevel)
2368 	{
2369 		mymenu[DETACH_OFFSET].text = N_("_Detach");
2370 		mymenu[CLOSE_OFFSET].text = N_("_Close");
2371 	}
2372 	else
2373 	{
2374 		mymenu[DETACH_OFFSET].text = N_("_Attach");
2375 		mymenu[CLOSE_OFFSET].text = N_("_Close");
2376 	}
2377 
2378 	while (1)
2379 	{
2380 		item = NULL;
2381 		if (mymenu[i].id == MENU_ID_USERMENU && !prefs.hex_gui_usermenu)
2382 		{
2383 			i++;
2384 			continue;
2385 		}
2386 
2387 		switch (mymenu[i].type)
2388 		{
2389 		case M_NEWMENU:
2390 			if (menu)
2391 				gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
2392 			item = menu = gtk_menu_new ();
2393 			if (mymenu[i].id == MENU_ID_USERMENU)
2394 				usermenu = menu;
2395 			menu_item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
2396 			/* record the English name for /menu */
2397 			g_object_set_data (G_OBJECT (menu_item), "name", mymenu[i].text);
2398 #ifdef HAVE_GTK_MAC /* Added to app menu, see below */
2399 			if (!bar || mymenu[i].id != MENU_ID_HEXCHAT)
2400 #endif
2401 				gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item);
2402 			gtk_widget_show (menu_item);
2403 			break;
2404 
2405 		case M_MENUPIX:
2406 			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, FALSE);
2407 			goto normalitem;
2408 
2409 		case M_MENUSTOCK:
2410 			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE);
2411 			goto normalitem;
2412 
2413 		case M_MENUITEM:
2414 			item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
2415 normalitem:
2416 			if (mymenu[i].key != 0)
2417 				gtk_widget_add_accelerator (item, "activate", accel_group,
2418 										mymenu[i].key,
2419 										mymenu[i].key == GDK_KEY_F1 ? 0 :
2420 										mymenu[i].key == GDK_KEY_w ? close_mask :
2421 										(g_ascii_isupper (mymenu[i].key)) ?
2422 											STATE_SHIFT | STATE_CTRL :
2423 											STATE_CTRL,
2424 										GTK_ACCEL_VISIBLE);
2425 			if (mymenu[i].callback)
2426 				g_signal_connect (G_OBJECT (item), "activate",
2427 										G_CALLBACK (mymenu[i].callback), 0);
2428 			if (submenu)
2429 				gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
2430 			else
2431 				gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2432 			gtk_widget_show (item);
2433 			break;
2434 
2435 		case M_MENUTOG:
2436 			item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text));
2437 togitem:
2438 			/* must avoid callback for Radio buttons */
2439 			GTK_CHECK_MENU_ITEM (item)->active = mymenu[i].state;
2440 			/*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
2441 													 mymenu[i].state);*/
2442 			if (mymenu[i].key != 0)
2443 				gtk_widget_add_accelerator (item, "activate", accel_group,
2444 											mymenu[i].key,
2445 											mymenu[i].id == MENU_ID_FULLSCREEN ? 0 :
2446 											mymenu[i].id == MENU_ID_AWAY ? away_mask :
2447 											STATE_CTRL, GTK_ACCEL_VISIBLE);
2448 			if (mymenu[i].callback)
2449 				g_signal_connect (G_OBJECT (item), "toggled",
2450 									G_CALLBACK (mymenu[i].callback), NULL);
2451 
2452 			if (submenu)
2453 				gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
2454 			else
2455 				gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2456 			gtk_widget_show (item);
2457 			gtk_widget_set_sensitive (item, mymenu[i].sensitive);
2458 			break;
2459 
2460 		case M_MENURADIO:
2461 			item = gtk_radio_menu_item_new_with_mnemonic (group, _(mymenu[i].text));
2462 			group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
2463 			goto togitem;
2464 
2465 		case M_SEP:
2466 			item = gtk_menu_item_new ();
2467 			gtk_widget_set_sensitive (item, FALSE);
2468 			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2469 			gtk_widget_show (item);
2470 			break;
2471 
2472 		case M_MENUSUB:
2473 			group = NULL;
2474 			submenu = gtk_menu_new ();
2475 			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE);
2476 			/* record the English name for /menu */
2477 			g_object_set_data (G_OBJECT (item), "name", mymenu[i].text);
2478 			gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
2479 			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2480 			gtk_widget_show (item);
2481 			break;
2482 
2483 		/*case M_END:*/ default:
2484 			if (!submenu)
2485 			{
2486 				if (menu)
2487 				{
2488 					gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
2489 					menu_add_plugin_mainmenu_items (menu_bar);
2490 				}
2491 				if (usermenu)
2492 					usermenu_create (usermenu);
2493 				return (menu_bar);
2494 			}
2495 			submenu = NULL;
2496 		}
2497 
2498 		/* record this GtkWidget * so it's state might be changed later */
2499 		if (mymenu[i].id != 0 && menu_widgets)
2500 			/* this ends up in sess->gui->menu_item[MENU_ID_XXX] */
2501 			menu_widgets[mymenu[i].id] = item;
2502 
2503 #ifdef HAVE_GTK_MAC
2504 		/* We want HexChat to be the app menu, not including Quit or HexChat itself */
2505 		if (bar && item && i <= CLOSE_OFFSET + 1 && mymenu[i].id != MENU_ID_HEXCHAT)
2506 		{
2507 			if (!submenu || mymenu[i].type == M_MENUSUB)
2508 				gtkosx_application_insert_app_menu_item (osx_app, item, appmenu_offset++);
2509 		}
2510 #endif
2511 
2512 		i++;
2513 	}
2514 }
2515