1 /* XQF - Quake server browser and launcher
2  * Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17  */
18 
19 #include "gnuconfig.h"
20 
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <stdlib.h>     /* atoi */
24 #include <sys/socket.h> /* inet_ntoa */
25 #include <netinet/in.h> /* inet_ntoa */
26 #include <arpa/inet.h>  /* inet_ntoa */
27 #include <time.h>       /* time */
28 #include <string.h>     /* strlen */
29 #include <ctype.h>      /* isspace */
30 #include <getopt.h>
31 
32 // select, fork, pipe...
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <signal.h>     /* kill... */
38 #include <sys/wait.h>
39 
40 
41 #ifdef ENABLE_NLS
42 #  include <locale.h>
43 #endif
44 
45 #include <gtk/gtk.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <gdk-pixbuf/gdk-pixbuf.h>
48 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
49 
50 #include "i18n.h"
51 #include "xqf.h"
52 #include "xqf-ui.h"
53 #include "game.h"
54 #include "stat.h"
55 #include "source.h"
56 #include "pref.h"
57 #include "filter.h"
58 #include "flt-player.h"
59 #include "skin.h"
60 #include "dialogs.h"
61 #include "utils.h"
62 #include "server.h"
63 #include "launch.h"
64 #include "host.h"
65 #include "xutils.h"
66 #include "srv-list.h"
67 #include "srv-info.h"
68 #include "srv-prop.h"
69 #include "rc.h"
70 #include "pixmaps.h"
71 #include "rcon.h"
72 #include "statistics.h"
73 #include "psearch.h"
74 #include "addserver.h"
75 #include "addmaster.h"
76 #include "sort.h"
77 #include "menus.h"
78 #include "config.h"
79 #include "debug.h"
80 #include "redial.h"
81 #include "splash.h"
82 #include "loadpixmap.h"
83 #include "trayicon.h"
84 #include "scripts.h"
85 #include "tga/memtopixmap.h"
86 
87 #ifdef USE_GEOIP
88 #include "country-filter.h"
89 #endif
90 
91 static const char gslisthome[] = "http://aluigi.altervista.org/papers.htm#gslist";
92 
93 static const char required_qstat_version[]="2.10";
94 
95 time_t xqf_start_time;
96 
97 int dontlaunch = 0;
98 
99 int event_type = 0;
100 
101 char* xqf_PACKAGE_DATA_DIR = PACKAGE_DATA_DIR;
102 char* xqf_LOCALEDIR = LOCALEDIR;
103 
104 char* qstat_configfile = NULL;
105 
106 GtkWidget *main_window = NULL;
107 GtkWidget *source_ctree = NULL;
108 GtkCList  *server_clist = NULL;
109 GtkCList  *player_clist = NULL;
110 GtkCTree  *srvinf_ctree = NULL;
111 
112 GtkEditable *selection_manager = NULL;
113 
114 GSList *cur_source = NULL;          /* GSList <struct master *> */
115 GSList *cur_server_list = NULL;     /* GSList <struct server *> */
116 GSList *cur_userver_list = NULL;    /* GSList <struct userver *> */
117 
118 struct server *cur_server = NULL;
119 
120 struct stat_job *stat_process = NULL;
121 
122 static GtkWidget *main_toolbar = NULL;
123 static GtkWidget *main_status_bar = NULL;
124 static GtkWidget *main_filter_status_bar = NULL;
125 static GtkWidget *main_progress_bar = NULL;
126 
127 static char *progress_bar_str = NULL;
128 
129 // static GtkWidget *server_filter_menu = NULL; /* baa */
130 
131 static GtkWidget *server_menu = NULL;
132 static GtkWidget *source_menu = NULL;
133 static GtkWidget *player_menu = NULL;
134 static GtkWidget *server_info_menu = NULL;
135 
136 static GtkWidget *connect_menu_item = NULL;
137 static GtkWidget *observe_menu_item = NULL;
138 static GtkWidget *record_menu_item = NULL;
139 static GtkWidget *favadd_menu_item = NULL;
140 static GtkWidget *add_menu_item = NULL;
141 static GtkWidget *delete_menu_item = NULL;
142 static GtkWidget *refresh_menu_item = NULL;
143 static GtkWidget *refrsel_menu_item = NULL;
144 static GtkWidget *resolve_menu_item = NULL;
145 static GtkWidget *properties_menu_item = NULL;
146 static GtkWidget *rcon_menu_item = NULL;
147 // static GtkWidget *cancel_redial_menu_item = NULL;
148 
149 static GtkWidget *file_quit_menu_item = NULL;
150 static GtkWidget *file_statistics_menu_item = NULL;
151 
152 static GtkWidget *edit_add_menu_item = NULL;
153 static GtkWidget *edit_favadd_menu_item = NULL;
154 static GtkWidget *edit_delete_menu_item = NULL;
155 static GtkWidget *edit_update_master_builtin_menu_item = NULL;
156 static GtkWidget *edit_update_master_gslist_menu_item = NULL;
157 static GtkWidget *edit_add_master_menu_item = NULL;
158 static GtkWidget *edit_edit_master_menu_item = NULL;
159 static GtkWidget *edit_delete_master_menu_item = NULL;
160 static GtkWidget *edit_clear_master_servers_menu_item = NULL;
161 static GtkWidget *edit_find_player_menu_item = NULL;
162 static GtkWidget *edit_find_again_menu_item = NULL;
163 
164 // rmb popup
165 static GtkWidget *source_add_master_menu_item = NULL;
166 static GtkWidget *source_edit_master_menu_item = NULL;
167 static GtkWidget *source_delete_master_menu_item = NULL;
168 static GtkWidget *source_clear_master_servers_menu_item = NULL;
169 
170 static GtkWidget *view_refresh_menu_item = NULL;
171 static GtkWidget *view_refrsel_menu_item = NULL;
172 static GtkWidget *view_update_menu_item = NULL;
173 
174 GtkWidget *view_hostnames_menu_item = NULL;
175 GtkWidget *view_defport_menu_item = NULL;
176 
177 static GtkWidget *server_connect_menu_item = NULL;
178 static GtkWidget *server_observe_menu_item = NULL;
179 static GtkWidget *server_record_menu_item = NULL;
180 static GtkWidget *server_favadd_menu_item = NULL;
181 static GtkWidget *server_delete_menu_item = NULL;
182 static GtkWidget *server_resolve_menu_item = NULL;
183 static GtkWidget *server_properties_menu_item = NULL;
184 static GtkWidget *server_rcon_menu_item = NULL;
185 // static GtkWidget *server_cancel_redial_menu_item = NULL;
186 
187 static GtkWidget *server_serverfilter_menu_item = NULL;
188 static GArray* server_filter_menu_items;
189 
190 static GtkWidget *player_filter_menu_item = NULL;
191 
192 static GtkWidget *update_button = NULL;
193 static GtkWidget *refresh_button = NULL;
194 static GtkWidget *refrsel_button = NULL;
195 static GtkWidget *stop_button = NULL;
196 
197 static GtkWidget *connect_button = NULL;
198 // static GtkWidget *observe_button = NULL;
199 // static GtkWidget *record_button = NULL;
200 
201 static GtkWidget *filter_buttons[FILTERS_TOTAL] = {0};
202 
203 /* filter widgtet for toolbar */
204 // static  GtkWidget *filter_option_menu_toolbar;
205 
206 static GtkWidget *player_skin_popup = NULL;
207 static GtkWidget *player_skin_popup_preview = NULL;
208 /*
209    static GtkWidget *server_filter_1_widget = NULL;
210    static GtkWidget *server_filter_2_widget = NULL;
211    static GtkWidget *server_filter_3_widget = NULL;
212 */
213 
214 // XXX: GtkWidget *server_filter_widget[MAX_SERVER_FILTERS + 3];
215 
216 static gboolean check_launch (struct condef* con);
217 static void refresh_selected_callback (GtkWidget *widget, gpointer data);
218 static void launch_close_handler_part2(struct condef *con);
219 
220 static void copy_text_to_clipboard(const char* text);
221 
222 /** build server filter menu for menubar */
223 static GtkWidget* create_filter_menu();
224 // static GtkWidget* create_filter_menu_toolbar();
225 // static GtkWidget* filter_menu = NULL; // need to store that for toggling the checkboxes
226 static GSList* filter_menu_radio_buttons = NULL; // for finding the widgets to activate
227 
228 static int redialserver = 0;
229 
sighandler_debug(int signum)230 static void sighandler_debug(int signum) {
231 	if (signum == SIGUSR1) {
232 		set_debug_level(get_debug_level()+1);
233 	}
234 	else if (signum == SIGUSR2) {
235 		set_debug_level(get_debug_level()-1);
236 	}
237 
238 	debug(0,"debug level now at %d", get_debug_level());
239 }
240 
241 // returns 0 if equal, -1 if too old, 1 if have > expected
compare_qstat_version(const char * have,const char * expected)242 int compare_qstat_version (const char* have, const char* expected) {
243 	int have_major, expected_major;
244 	int have_minor, expected_minor;
245 	char have_pl=0, expected_pl=0;
246 	const char* have_pos1=NULL, *expected_pos1=NULL;
247 	const char* have_pos2=NULL, *expected_pos2=NULL;
248 	char* buf;
249 
250 	debug(3,"compare_qstat_version(%s,%s)",have,expected);
251 
252 	if (!strcmp(have,expected)) {
253 		return 0;
254 	}
255 
256 	have_pos1 = strchr(have,'.');
257 	expected_pos1 = strchr(expected,'.');
258 
259 	if (!have_pos1 || !expected_pos1) {
260 		return -1;
261 	}
262 
263 	buf = g_strndup(have,have_pos1-have);
264 	have_major = atoi(buf);
265 	g_free(buf);
266 	buf = g_strndup(expected,expected_pos1-expected);
267 	expected_major = atoi(buf);
268 	g_free(buf);
269 
270 	debug(3,"compare_qstat_version -- compare major %d %d",have_major,expected_major);
271 	if (have_major < expected_major) {
272 		return -1;
273 	}
274 	if (have_major > expected_major) {
275 		return 1;
276 	}
277 
278 	have_pos1++;
279 	expected_pos1++;
280 
281 	for (have_pos2=have_pos1;
282 			have_pos2 && *have_pos2 && isdigit(*have_pos2);
283 			have_pos2++);
284 	for (expected_pos2=expected_pos1;
285 			expected_pos2 && *expected_pos2 && isdigit(*expected_pos2);
286 			expected_pos2++);
287 
288 	buf = g_strndup(have_pos1,have_pos2-have_pos1);
289 	have_minor = atoi(buf);
290 	g_free(buf);
291 	buf = g_strndup(expected_pos1,expected_pos2-expected_pos1);
292 	expected_minor = atoi(buf);
293 	g_free(buf);
294 
295 	debug(3,"compare_qstat_version -- compare minor %d %d",have_minor,expected_minor);
296 	if (have_minor < expected_minor) {
297 		return -1;
298 	}
299 	if (have_minor > expected_minor) {
300 		return 1;
301 	}
302 
303 	if (have_pos2 && *have_pos2) have_pl=*have_pos2;
304 	if (expected_pos2 && *expected_pos2) expected_pl=*expected_pos2;
305 
306 	debug(3,"compare_qstat_version -- compare pl %c %c",have_pl,expected_pl);
307 	if (!have_pl && expected_pl) {
308 		return -1;
309 	}
310 	if (have_pl && expected_pl && have_pl < expected_pl) {
311 		return -1;
312 	}
313 
314 	return 1;
315 }
316 
qstat_version_string(struct external_program_connection * conn)317 void qstat_version_string(struct external_program_connection* conn) {
318 	static const char search_for[] = "qstat version";
319 	const char *ptr, *version_end;
320 	char* found_version = NULL;
321 
322 	if (!conn) {
323 		return;
324 	}
325 
326 	// we already found a valid version string
327 	if (conn->result) {
328 		return;
329 	}
330 	if (!conn->current_line) {
331 		return;
332 	}
333 
334 	if (!strncmp(conn->current_line,search_for,strlen(search_for))) {
335 		ptr = conn->current_line + strlen(search_for);
336 		// skip whitespace
337 		for (;isspace(*ptr);++ptr);
338 		if (!*ptr) {
339 			conn->result = FALSE;
340 			return;
341 		}
342 		// skip until end of version string
343 		for (version_end=ptr;
344 				version_end &&
345 				*version_end != '\0' && !isspace(*version_end);
346 				++version_end);
347 		found_version=g_strndup(ptr,version_end-ptr);
348 		// debug(0,"found version <%s>",found_version);
349 
350 		if (compare_qstat_version(found_version,required_qstat_version)>=0) {
351 			conn->result=TRUE;
352 		}
353 
354 		g_free(found_version);
355 	}
356 }
357 
check_qstat_version()358 int check_qstat_version() {
359 	char* cmd[] = {QSTAT_EXEC,NULL};
360 
361 	return external_program_foreach_line(cmd, qstat_version_string, NULL);
362 }
363 
reset_main_status_bar()364 void reset_main_status_bar() {
365 	// Reset bottom left status bar to show number of servers
366 	print_status (main_status_bar,
367 			ngettext(_("%d server"),_("%d servers"), server_clist->rows),
368 			server_clist->rows);
369 }
370 
set_widgets_sensitivity(void)371 void set_widgets_sensitivity (void) {
372 	GList *selected = server_clist->selection;
373 	int sens;
374 	int i;
375 	int source_is_favorites;
376 	int masters_to_update;
377 	int masters_to_delete;
378 
379 	/*
380 	 * Every button with callback that can modify its sensitivity
381 	 * should be explicitly put to GTK_STATE_NORMAL state before
382 	 * changing its insensitivity
383 	 */
384 
385 	source_is_favorites = (cur_source != NULL &&
386 			cur_source->next == NULL &&
387 			(struct master *) cur_source->data == favorites);
388 
389 	if (source_is_favorites) {
390 		masters_to_update = masters_to_delete = FALSE;
391 	}
392 	else {
393 		masters_to_update = source_has_masters_to_update (cur_source);
394 		masters_to_delete = source_has_masters_to_delete (cur_source);
395 	}
396 
397 	sens = (!stat_process && cur_server);
398 
399 	gtk_widget_set_sensitive (properties_menu_item, sens);
400 	gtk_widget_set_sensitive (server_properties_menu_item, sens);
401 
402 	sens = (!stat_process && cur_server &&
403 			(games[cur_server->type].flags & GAME_CONNECT) != 0);
404 
405 	gtk_widget_set_sensitive (connect_menu_item, sens);
406 	gtk_widget_set_sensitive (server_connect_menu_item, sens);
407 
408 	gtk_widget_set_state (connect_button, GTK_STATE_NORMAL);
409 	gtk_widget_set_sensitive (connect_button, sens);
410 
411 	sens = (!stat_process && cur_server &&
412 			(games[cur_server->type].flags & GAME_SPECTATE) != 0 &&
413 			(cur_server->flags & SERVER_SPECTATE) != 0);
414 
415 	gtk_widget_set_sensitive (observe_menu_item, sens);
416 	gtk_widget_set_sensitive (server_observe_menu_item, sens);
417 
418 	// gtk_widget_set_state (observe_button, GTK_STATE_NORMAL);
419 	// gtk_widget_set_sensitive (observe_button, sens);
420 
421 	sens = (!stat_process && cur_server &&
422 			(games[cur_server->type].flags & GAME_RECORD) != 0);
423 
424 	gtk_widget_set_sensitive (record_menu_item, sens);
425 	gtk_widget_set_sensitive (server_record_menu_item, sens);
426 
427 	// gtk_widget_set_state (record_button, GTK_STATE_NORMAL);
428 	// gtk_widget_set_sensitive (record_button, sens);
429 
430 	sens = (!stat_process && cur_server &&
431 			(games[cur_server->type].flags & GAME_RCON) != 0);
432 
433 	gtk_widget_set_sensitive (rcon_menu_item, sens);
434 	gtk_widget_set_sensitive (server_rcon_menu_item, sens);
435 
436 	sens = (!stat_process && selected);
437 
438 	gtk_widget_set_sensitive (refrsel_menu_item, sens);
439 	gtk_widget_set_sensitive (view_refrsel_menu_item, sens);
440 
441 	gtk_widget_set_state (refrsel_button, GTK_STATE_NORMAL);
442 	gtk_widget_set_sensitive (refrsel_button, sens);
443 
444 	gtk_widget_set_sensitive (resolve_menu_item, sens);
445 	gtk_widget_set_sensitive (server_resolve_menu_item, sens);
446 
447 	sens = (!stat_process);
448 
449 	gtk_widget_set_sensitive (file_statistics_menu_item, sens);
450 	gtk_widget_set_sensitive (add_menu_item, sens);
451 	gtk_widget_set_sensitive (edit_add_menu_item, sens);
452 	gtk_widget_set_sensitive (edit_update_master_builtin_menu_item, sens);
453 	gtk_widget_set_sensitive (edit_update_master_gslist_menu_item, sens);
454 	gtk_widget_set_sensitive (edit_add_master_menu_item, sens);
455 	gtk_widget_set_sensitive (edit_find_player_menu_item, sens);
456 	gtk_widget_set_sensitive (edit_find_again_menu_item, sens);
457 	gtk_widget_set_sensitive (player_filter_menu_item, sens);
458 	gtk_widget_set_sensitive (source_ctree, sens);
459 
460 	sens = (!stat_process && selected && !source_is_favorites);
461 
462 	gtk_widget_set_sensitive (favadd_menu_item, sens);
463 	gtk_widget_set_sensitive (edit_favadd_menu_item, sens);
464 	gtk_widget_set_sensitive (server_favadd_menu_item, sens);
465 
466 #if 0
467 	sens = (!stat_process && selected && source_is_favorites);
468 
469 	gtk_widget_set_sensitive (delete_menu_item, sens);
470 	gtk_widget_set_sensitive (edit_delete_menu_item, sens);
471 	gtk_widget_set_sensitive (server_delete_menu_item, sens);
472 #endif
473 
474 	sens = (!stat_process && masters_to_delete);
475 
476 	gtk_widget_set_sensitive (edit_delete_master_menu_item, sens);
477 	gtk_widget_set_sensitive (edit_clear_master_servers_menu_item, sens);
478 	gtk_widget_set_sensitive (source_delete_master_menu_item, sens);
479 	gtk_widget_set_sensitive (source_clear_master_servers_menu_item, sens);
480 
481 	// you can only edit one server a time, no groups and no favorites
482 	sens = (cur_source && cur_source->next == NULL
483 			&& ! ((struct master *) cur_source->data)->isgroup
484 			&& ! source_is_favorites);
485 
486 	gtk_widget_set_sensitive (source_edit_master_menu_item, sens);
487 	gtk_widget_set_sensitive (edit_edit_master_menu_item, sens);
488 
489 	sens = (!stat_process && (server_clist->rows > 0));
490 
491 	gtk_widget_set_sensitive (refresh_menu_item, sens);
492 	gtk_widget_set_sensitive (view_refresh_menu_item, sens);
493 
494 	gtk_widget_set_state (refresh_button, GTK_STATE_NORMAL);
495 	gtk_widget_set_sensitive (refresh_button, sens);
496 
497 	gtk_widget_set_sensitive (view_hostnames_menu_item, sens);
498 	gtk_widget_set_sensitive (view_defport_menu_item, sens);
499 
500 	sens = (!stat_process && masters_to_update);
501 
502 	gtk_widget_set_sensitive (view_update_menu_item, sens);
503 
504 	gtk_widget_set_state (update_button, GTK_STATE_NORMAL);
505 	gtk_widget_set_sensitive (update_button, sens);
506 
507 	sens = (stat_process != NULL);
508 
509 	gtk_widget_set_state (stop_button, GTK_STATE_NORMAL);
510 	gtk_widget_set_sensitive (stop_button, sens);
511 
512 	sens = (stat_process == NULL);
513 
514 	for (i = 0; i < FILTERS_TOTAL; i++) {
515 		if (!filter_buttons[i]) {
516 			continue;
517 		}
518 		gtk_widget_set_state(filter_buttons[ i ],GTK_STATE_NORMAL);
519 		gtk_widget_set_sensitive (filter_buttons[i], sens);
520 		if (GTK_IS_TOGGLE_BUTTON(filter_buttons[i]) && GTK_TOGGLE_BUTTON(filter_buttons[i])->active) {
521 			gtk_widget_set_state(filter_buttons[ i ],GTK_STATE_ACTIVE);
522 		}
523 	}
524 #if 0
525 	// grey out button if not redialing
526 	sens = (redialserver == 1);
527 	gtk_widget_set_sensitive (cancel_redial_menu_item, sens);
528 	gtk_widget_set_sensitive (server_cancel_redial_menu_item, sens);
529 #endif
530 }
531 
532 
533 static int forced_filters_flag = FALSE;
534 
535 
set_filters(unsigned char mask)536 static void set_filters (unsigned char mask) {
537 	unsigned n;
538 	int i;
539 
540 	forced_filters_flag = TRUE;
541 
542 	cur_filter = mask;
543 
544 	for (i = 0, n = 1; i < FILTERS_TOTAL; i++, n <<= 1) {
545 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (filter_buttons[i]),
546 				((cur_filter & n) != 0)? TRUE : FALSE);
547 	}
548 
549 	forced_filters_flag = FALSE;
550 }
551 
552 
filter_toggle_callback(GtkWidget * widget,unsigned char mask)553 static void filter_toggle_callback (GtkWidget *widget, unsigned char mask) {
554 
555 
556 	if (!forced_filters_flag) {
557 		cur_filter ^= mask;
558 		server_clist_build_filtered (cur_server_list, FALSE); /* in srv-list.c */
559 		reset_main_status_bar();
560 	}
561 }
562 
563 // iterate through radio buttons and activate the one for the current server
564 // filter
filter_menu_activate_current()565 static void filter_menu_activate_current() {
566 	unsigned int count = 0;
567 	GSList* rbgroup = filter_menu_radio_buttons;
568 	GtkWidget* widget = NULL;
569 
570 	while (rbgroup) {
571 		if (GTK_IS_CHECK_MENU_ITEM(rbgroup->data)) {
572 			if (count == current_server_filter) {
573 				widget = GTK_WIDGET(rbgroup->data);
574 				break;
575 			}
576 			count++;
577 		}
578 		rbgroup=rbgroup->next;
579 	}
580 
581 	if (widget) {
582 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE);
583 	}
584 }
585 
586 
587 /*refresh filtermenu on toolbar*/
588 
set_filter_option_menu_toolbar(void)589 void set_filter_option_menu_toolbar (void) {
590 
591 	/*
592 	   gtk_option_menu_set_menu (GTK_OPTION_MENU (filter_option_menu_toolbar), create_filter_menu_toolbar());
593 	   gtk_option_menu_set_history(GTK_OPTION_MENU(filter_option_menu_toolbar), current_server_filter);
594 	*/
595 }
596 
597 
set_server_filter_menu_list_text(void)598 void set_server_filter_menu_list_text(void){
599 
600 	/* baa -- Set the names of the filters if they have been set in
601 	   the config file. The server_filters is defined in filter.h
602 	*/
603 
604 	char status_buf[64];
605 	char* name;
606 
607 #if 0
608 	for (i = 0; i < MAX_SERVER_FILTERS; i++) {
609 
610 		if (i == 0){
611 			if (current_server_filter == i) {
612 				//server filter
613 				snprintf(buf, 64, _("None <--"));
614 			}
615 			else {
616 				snprintf(buf, 64, _("None"));
617 			}
618 		}
619 		else {
620 			if (server_filters[i].filter_name && strlen(server_filters[i].filter_name)){
621 
622 				if (current_server_filter == i) {
623 					snprintf(buf, 64, "%s <--", server_filters[i].filter_name);
624 				}
625 				else {
626 					snprintf(buf, 64, "%s", server_filters[i].filter_name);
627 				}
628 
629 			}
630 			else {
631 
632 				if (current_server_filter == i) {
633 					snprintf(buf, 64, _("Filter %d <--"), i);
634 				}
635 				else {
636 					snprintf(buf, 64, _("Filter %d"), i);
637 				}
638 
639 			}
640 		}
641 
642 		if (server_filter_widget[i + filter_start_index ] && GTK_BIN (server_filter_widget[i + filter_start_index])->child) 		{
643 			GtkWidget *child = GTK_BIN (server_filter_widget[i + filter_start_index ])->child;
644 			if (GTK_IS_LABEL (child)) {
645 				gtk_label_set (GTK_LABEL (child), buf);
646 			}
647 		}
648 	}
649 
650 #endif
651 
652 
653 	/* Show the active filter on the status bar
654 	   -- Add code to indicate if the filter button is checked.
655 	*/
656 	if (current_server_filter == 0) {
657 		snprintf(status_buf, 64, _("No Server Filter Active"));
658 	}
659 	else {
660 		name = g_array_index (server_filters, struct server_filter_vars*, current_server_filter-1)->filter_name;
661 		if (name) {
662 			snprintf(status_buf, 64, _("Server Filter: %s"), name);
663 		}
664 		else {
665 			snprintf(status_buf, 64, _("Server Filter: %d"), current_server_filter);
666 			xqf_error("this is a bug");
667 		}
668 	}
669 
670 	print_status (main_filter_status_bar, status_buf);
671 
672 	reset_main_status_bar();
673 
674 }
675 
676 
server_filter_select_callback(GtkWidget * widget,int number)677 static void server_filter_select_callback (GtkWidget *widget, int number) {
678 
679 	if (!GTK_IS_CHECK_MENU_ITEM(widget)) {
680 		g_warning("no check menu item");
681 		return;
682 	}
683 
684 	if (GTK_CHECK_MENU_ITEM(widget)->active == 0) {
685 		// signal was triggered for deactivation
686 		return;
687 	}
688 
689 	current_server_filter = number;
690 
691 	filters[FILTER_SERVER].changed = FILTER_CHANGED;
692 	filters[FILTER_SERVER].last_changed = filter_time_inc();
693 
694 	server_clist_build_filtered (cur_server_list, FALSE); /* in srv-list.c */
695 	set_server_filter_menu_list_text ();
696 
697 	/* refresh optionmenu on toolbar*/
698 
699 	set_filter_option_menu_toolbar();
700 
701 	config_push_prefix ("/" CONFIG_FILE "/Server Filter");
702 	config_set_int ("current_server_filter", current_server_filter);
703 	config_pop_prefix ();
704 
705 	return;
706 }
707 
708 /* need new one to refresh filter radio buttons in menu */
709 #if 0
710 static void server_filter_select_callback_toolbar (GtkWidget *widget, int number) {
711 
712 	current_server_filter = number;
713 
714 	/*apply changes to radio buttons in menu*/
715 
716 	filter_menu_activate_current();
717 
718 	return;
719 }
720 #endif
721 
722 
start_preferences_dialog(GtkWidget * widget,int page_num)723 static void start_preferences_dialog (GtkWidget *widget, int page_num) {
724 	preferences_dialog (page_num);
725 	set_toolbar_appearance (GTK_TOOLBAR (main_toolbar), default_toolbar_style, default_toolbar_tips);
726 }
727 
728 
start_filters_cfg_dialog(GtkWidget * widget,int page_num)729 static void start_filters_cfg_dialog (GtkWidget *widget, int page_num) {
730 	if (filters_cfg_dialog (page_num)) {
731 		config_sync ();
732 		rc_save ();
733 		gtk_menu_item_set_submenu (GTK_MENU_ITEM (server_serverfilter_menu_item), create_filter_menu());
734 		filter_menu_activate_current();
735 
736 		/* refresh optionmenu on toolbar*/
737 		set_filter_option_menu_toolbar();
738 
739 		/* refresh filter status*/
740 		set_server_filter_menu_list_text ();
741 
742 		//happes automagically   server_clist_build_filtered (cur_server_list, TRUE);
743 		player_clist_redraw ();
744 	}
745 }
746 
747 
update_server_lists_from_selected_source(void)748 static void update_server_lists_from_selected_source (void) {
749 	GSList *cur_masters = NULL;
750 
751 	debug (6, "update_server_lists_from_selected_source() --");
752 	if (cur_server_list) {
753 		debug (6, "update_server_lists_from_selected_source() -- Free cur_server_list %lx", cur_server_list);
754 		server_list_free (cur_server_list);
755 		cur_server_list = NULL;
756 	}
757 
758 	if (cur_userver_list) {
759 		userver_list_free (cur_userver_list);
760 		cur_userver_list = NULL;
761 	}
762 
763 	master_selection_to_lists (cur_source, &cur_masters, &cur_server_list, &cur_userver_list);
764 	collate_server_lists (cur_masters, &cur_server_list, &cur_userver_list);
765 }
766 
767 /**
768   update ui with aquired data during refresh and when refresh is done
769 */
stat_lists_refresh(struct stat_job * job)770 static int stat_lists_refresh (struct stat_job *job) {
771 	int items;
772 	int freeze;
773 
774 	items = g_slist_length (job->delayed.queued_servers) +
775 		g_slist_length (job->delayed.queued_hosts);
776 
777 	debug (6, "stat_lists_refresh() -- Job %lx, items %d", job,items);
778 
779 	if (items>100) {
780 		update_server_lists_from_selected_source ();
781 		server_clist_build_filtered (cur_server_list, TRUE);
782 		job->delayed.queued_servers = NULL;
783 		job->delayed.queued_hosts = NULL;
784 	}
785 	else if (items) {
786 		freeze = (items > 1) || default_refresh_sorts;
787 
788 		if (freeze) {
789 			gtk_clist_freeze (server_clist);
790 		}
791 
792 		g_slist_foreach (job->delayed.queued_servers, (GFunc) server_clist_refresh_server, NULL);
793 		server_list_free (job->delayed.queued_servers);
794 		job->delayed.queued_servers = NULL;
795 
796 		g_slist_foreach (job->delayed.queued_hosts, (GFunc) server_clist_show_hostname, NULL);
797 		host_list_free (job->delayed.queued_hosts);
798 		job->delayed.queued_hosts = NULL;
799 
800 		if (default_refresh_sorts) {
801 			gtk_clist_sort (server_clist);
802 		}
803 
804 		if (freeze) {
805 			gtk_clist_thaw (server_clist);
806 		}
807 	}
808 
809 	// print_status (main_status_bar, (progress_bar_str)? progress_bar_str : "", job->progress.done, job->progress.tasks);
810 	if (job->progress.tasks > 0) {
811 		progress_bar_set_percentage (main_progress_bar, ((float)job->progress.done) / job->progress.tasks);
812 	}
813 
814 	return TRUE;
815 }
816 
817 
stat_lists_state_handler(struct stat_job * job,enum stat_state state)818 static void stat_lists_state_handler (struct stat_job *job, enum stat_state state) {
819 	if (!main_window) {
820 		return;
821 	}
822 
823 	switch (state) {
824 
825 		case STAT_UPDATE_SOURCE:
826 			progress_bar_str = _("Updating lists...");
827 			if (default_show_tray_icon) {
828 				tray_icon_start_animation ();
829 			}
830 			break;
831 
832 		case STAT_RESOLVE_NAMES:
833 			progress_bar_str = _("Resolving host names: %d/%d");
834 			break;
835 
836 		case STAT_REFRESH_SERVERS:
837 			progress_bar_str = _("Refreshing: %d/%d");
838 			if (default_show_tray_icon) {
839 				tray_icon_start_animation ();
840 			}
841 			break;
842 
843 		case STAT_RESOLVE_HOSTS:
844 			progress_bar_str = _("Resolving host addresses: %d/%d");
845 			break;
846 
847 		default:
848 			progress_bar_str = NULL;
849 			break;
850 	}
851 
852 	progress_bar_start (main_progress_bar, state == STAT_UPDATE_SOURCE || job->progress.tasks <= 1);
853 
854 	stat_lists_refresh (job);   /* flush */
855 }
856 
857 
stat_lists_close_handler(struct stat_job * job,int killed)858 static void stat_lists_close_handler (struct stat_job *job, int killed) {
859 
860 	if (!main_window) {
861 		return;
862 	}
863 
864 	if (job->need_redraw) {
865 		update_server_lists_from_selected_source ();
866 		server_clist_build_filtered (cur_server_list, TRUE);
867 	}
868 	/*
869 	if (redialserver == 1) {
870 		print_status (main_status_bar, _("Waiting to redial server(s)..."));
871 	else {
872 	}
873 	*/
874 
875 	tray_icon_stop_animation ();
876 	reset_main_status_bar();
877 
878 	progress_bar_reset (main_progress_bar);
879 
880 	stat_process = NULL;
881 	set_widgets_sensitivity ();
882 }
883 
884 
stat_lists_server_handler(struct stat_job * job,struct server * s)885 static void stat_lists_server_handler (struct stat_job *job, struct server *s) {
886 	if (s == cur_server) {
887 		if (job->delayed.refresh_handler) {
888 			(*job->delayed.refresh_handler) (job);
889 		}
890 		player_clist_set_server (s);
891 		srvinf_ctree_set_server (s);
892 	}
893 }
894 
895 
stat_lists_master_handler(struct stat_job * job,struct master * m)896 static void stat_lists_master_handler (struct stat_job *job, struct master *m) {
897 	source_ctree_show_node_status (source_ctree, m);
898 }
899 
900 
stat_lists(GSList * masters,GSList * names,GSList * servers,GSList * hosts)901 static void stat_lists (GSList *masters, GSList *names, GSList *servers, GSList *hosts) {
902 
903 	if (stat_process || (!masters && !names && !servers && !hosts)) {
904 		return;
905 	}
906 	debug_increase_indent();
907 	debug (7, "stat_lists() -- Server List %p", servers);
908 
909 	stat_process = stat_job_create (masters, names, servers, hosts);
910 
911 	stat_process->delayed.refresh_handler = (GtkFunction) stat_lists_refresh;
912 
913 	stat_process->state_handlers = g_slist_prepend (stat_process->state_handlers, stat_lists_state_handler);
914 	stat_process->close_handlers = g_slist_prepend (stat_process->close_handlers, stat_lists_close_handler);
915 
916 	stat_process->server_handlers = g_slist_append (stat_process->server_handlers, stat_lists_server_handler);
917 	stat_process->master_handlers = g_slist_append (stat_process->master_handlers, stat_lists_master_handler);
918 
919 	stat_start (stat_process);
920 	set_widgets_sensitivity ();
921 	debug_decrease_indent();
922 }
923 
924 
stat_one_server(struct server * server)925 static void stat_one_server (struct server *server) {
926 	GSList *list;
927 
928 	debug (6, "Server %lx", server);
929 	if (!stat_process && server) {
930 		list = server_list_prepend (NULL, server);
931 		stat_lists (NULL, NULL, list, NULL);
932 	}
933 }
934 
launch_close_handler(struct stat_job * job,int killed)935 static void launch_close_handler (struct stat_job *job, int killed) {
936 	struct condef* con;
937 
938 	con = (struct condef *) job->data;
939 	job->data = NULL;
940 
941 	if (killed) {
942 		condef_free (con);
943 		return;
944 	}
945 
946 	gtk_timeout_add(0,(GtkFunction)check_launch, (gpointer)con);
947 }
948 
949 /** called from inside timer, always return FALSE to stop it */
check_launch(struct condef * con)950 static gboolean check_launch (struct condef* con) {
951 	struct server_props *props;
952 	gboolean launch = FALSE;
953 
954 	struct server *s;
955 
956 	if (!con) {
957 		return FALSE;
958 	}
959 
960 	s = con->s;
961 	props = properties (s);
962 
963 	if (props && props->sucks) {
964 		char* comment = props->comment;
965 		if (comment && strlen(comment)) {
966 			comment = g_strdup_printf(_("\n\nThe server sucks for the following reason:\n%s"), props->comment);
967 		}
968 		else {
969 			comment = NULL;
970 		}
971 		launch = dialog_yesno (NULL, 1, _("Yes"), _("No"),
972 				/* translator: %s = optional reason why the server sucks */
973 				_("You said this servers sucks.\nDo you want to risk a game this time?%s"), comment?comment:"");
974 
975 		g_free(comment);
976 
977 		if (!launch) {
978 			condef_free (con);
979 			return FALSE;
980 		}
981 	}
982 
983 	if (s->flags & SERVER_INCOMPATIBLE) {
984 		launch = dialog_yesno (NULL, 1, _("Yes"), _("No"),
985 				_("This server is not compatible with the version of %s you have"
986 					" installed.\nLaunch client anyway?"), games[s->type].name);
987 
988 		if (!launch) {
989 			condef_free (con);
990 			return FALSE;
991 		}
992 	}
993 
994 	if (s->ping >= MAX_PING) {
995 		launch = dialog_yesno (NULL, 1, _("Launch"), _("Cancel"),
996 				_("Server %s:%d is %s.\n\nLaunch client anyway?"),
997 				(s->host->name)? s->host->name : inet_ntoa (s->host->ip),
998 				s->port,
999 				(s->ping == MAX_PING)? "unreachable" : "down");
1000 		if (!launch) {
1001 			condef_free (con);
1002 			return FALSE;
1003 		}
1004 	}
1005 
1006 	if (!launch && !con->spectate && server_need_redial(s, props)) {
1007 		launch = dialog_yesnoredial (NULL, 1, _("Launch"), _("Cancel"), _("Redial"),
1008 				_("Server %s:%d is full.\n\nLaunch client anyway?"),
1009 				(s->host->name)? s->host->name : inet_ntoa (s->host->ip),
1010 				s->port);
1011 		if (!launch) {
1012 			condef_free (con);
1013 			return FALSE;
1014 		}
1015 		else if (launch==2)
1016 		{
1017 			redialserver = 1;
1018 
1019 			launch = redial_dialog(con->s, props);
1020 
1021 			if (launch == FALSE) {
1022 				condef_free (con);
1023 				return FALSE;
1024 			}
1025 		}
1026 		else
1027 			redialserver = 0;
1028 	}
1029 
1030 	launch_close_handler_part2(con);
1031 
1032 	return FALSE;
1033 }
1034 
1035 // stop XMMS if running
stopxmms()1036 static void stopxmms() {
1037 	char* xmmssocket = NULL;
1038 	pid_t pid;
1039 
1040 	if (!default_stopxmms) {
1041 		return;
1042 	}
1043 
1044 	xmmssocket = g_strdup_printf("/tmp/xmms_%s.0",g_get_user_name());
1045 
1046 	if (access(xmmssocket,R_OK)) {
1047 		debug(3,"xmms not running");
1048 		g_free(xmmssocket);
1049 		return;
1050 	}
1051 
1052 	pid = fork();
1053 	if (pid == 0) {
1054 		char *argv[3];
1055 		argv[0] = "xmms";
1056 		argv[1] = "-s";
1057 		argv[2] = NULL;
1058 		execvp(argv[0],argv);
1059 		_exit(EXIT_FAILURE);
1060 	}
1061 	else if (pid > 0) {
1062 		int status;
1063 		waitpid(pid,&status,0);
1064 
1065 		if (WIFEXITED(status)) {
1066 			debug(3,"xmms exited normally");
1067 		}
1068 		else {
1069 			debug(3,"xmms exited with status %d",WEXITSTATUS(status));
1070 		}
1071 		if (WIFSIGNALED(status)) {
1072 			debug(3,"xmms was killed by signal %d",WTERMSIG(status));
1073 		}
1074 	}
1075 
1076 	g_free(xmmssocket);
1077 }
1078 
launch_close_handler_part2(struct condef * con)1079 static void launch_close_handler_part2(struct condef *con) {
1080 	struct server_props *props;
1081 	int launch = FALSE;
1082 	int save = 0;
1083 	FILE *f;
1084 	char *fn;
1085 	char *temp_name;
1086 	char *temp_mod;
1087 	char *temp_game;
1088 
1089 	struct server *s;
1090 
1091 	stopxmms();
1092 
1093 	if (redialserver == 1) // was called from a redial
1094 		play_sound(sound_redial_success, 0);
1095 	else
1096 		play_sound(sound_server_connect, 0);
1097 
1098 	redialserver = 0; // Cancel any redialing
1099 
1100 	s = con->s;
1101 	props = properties (s);
1102 
1103 	debug(3,"rest of launch_close_handler"); // alex
1104 
1105 	if (con->spectate) {
1106 		if ((s->flags & SERVER_SP_PASSWORD) == 0) {
1107 			// XXX: what's this good for? looks useless to me -- ln
1108 			con->spectator_password = g_strdup ("1");
1109 		}
1110 		else {
1111 			if (props && props->spectator_password) {
1112 				con->spectator_password = g_strdup (props->spectator_password);
1113 			}
1114 			else {
1115 				con->spectator_password = enter_string_with_option_dialog (FALSE,
1116 						_("Save Password"), &save, _("Spectator Password:"));
1117 				if (!con->spectator_password) {
1118 					condef_free (con);
1119 					return;
1120 				}
1121 				if (save) {
1122 					if (!props) {
1123 						props = properties_new (s->host, s->port);
1124 					}
1125 					props->spectator_password = g_strdup (con->spectator_password);
1126 					props_save ();
1127 				}
1128 			}
1129 		}
1130 	}
1131 	else {
1132 		if (props && props->server_password) {
1133 			con->password = g_strdup (props->server_password);
1134 		}
1135 		else if ((s->flags & SERVER_PASSWORD) != 0) {
1136 			con->password = enter_string_with_option_dialog (FALSE,
1137 					_("Save Password"), &save, _("Server Password:"));
1138 			if (!con->password) {
1139 				condef_free (con);
1140 				return;
1141 			}
1142 			if (save) {
1143 				if (!props) {
1144 					props = properties_new (s->host, s->port);
1145 				}
1146 				props->server_password = g_strdup (con->password);
1147 				props_save ();
1148 			}
1149 		}
1150 	}
1151 
1152 	// con->server = g_strdup_printf ("%s:%5d", inet_ntoa (s->host->ip), s->port);
1153 	con->server = g_strdup_printf ("%s:%d", inet_ntoa (s->host->ip), s->port);
1154 	con->gamedir = g_strdup (s->game);
1155 
1156 	if (props && props->rcon_password) {
1157 		con->rcon_password = g_strdup (props->rcon_password);
1158 	}
1159 
1160 	if (props && props->custom_cfg) {
1161 		con->custom_cfg = g_strdup (props->custom_cfg);
1162 	}
1163 
1164 
1165 	launch = client_launch (con, TRUE);
1166 	condef_free (con);
1167 
1168 	if (!launch) {
1169 		return;
1170 	}
1171 
1172 	// Save address etc to LaunchInfo.txt
1173 	if (default_launchinfo) {
1174 		fn = file_in_dir (user_rcdir, LAUNCHINFO_FILE);
1175 
1176 		f = fopen (fn, "w");
1177 		if (f) {
1178 
1179 			temp_name = s->name;
1180 			temp_game = s->game;
1181 			temp_mod = s->gametype;
1182 
1183 			if (!temp_name) {
1184 				temp_name = "";
1185 			}
1186 
1187 			fprintf (f, "GameType %s\n", games[s->type].name);
1188 			fprintf (f, "ServerName %s\n", temp_name);
1189 			fprintf (f, "ServerAddr %s:%d\n", inet_ntoa (s->host->ip),
1190 					s->port);
1191 
1192 			fprintf (f, "ServerMod ");
1193 			if (temp_game) {
1194 				fprintf (f, "%s", temp_game);
1195 			}
1196 			if (temp_game&&temp_mod) {
1197 				fprintf (f, ", ");
1198 			}
1199 			if (temp_mod) {
1200 				fprintf (f, "%s", temp_mod);
1201 			}
1202 			fprintf (f, "\n");
1203 
1204 			fclose (f);
1205 		}
1206 		g_free (fn);
1207 	}
1208 
1209 	// Launch pre-launch script
1210 	if (default_prelaunchexec) {
1211 		if (fork() == 0) {
1212 			char *launchargv[4];
1213 			launchargv[0] = g_strdup_printf("%s/PreLaunch",user_rcdir);
1214 			launchargv[1] = games[s->type].qstat_str;
1215 			launchargv[2] = g_strdup_printf("%s:%d", inet_ntoa (s->host->ip), s->port);
1216 			launchargv[3] = NULL;
1217 			execv(launchargv[0],launchargv);
1218 			xqf_error("PreLaunch failed");
1219 			_exit(EXIT_FAILURE);
1220 		}
1221 	}
1222 
1223 	if (main_window && default_iconify && !default_terminate) {
1224 		iconify_window (main_window->window);
1225 	}
1226 
1227 	if (main_window && default_terminate) {
1228 		gtk_widget_destroy (main_window);
1229 	}
1230 }
1231 
1232 
launch_server_handler(struct stat_job * job,struct server * s)1233 static void launch_server_handler (struct stat_job *job, struct server *s) {
1234 
1235 	server_clist_refresh_server (s);
1236 
1237 	if (s == cur_server) {
1238 		player_clist_set_server (s);
1239 		srvinf_ctree_set_server (s);
1240 	}
1241 
1242 	// no connection defined, maybe because of a hostname instead of ip specified
1243 	// on command line. just take first server to launch
1244 	if (!job->data) {
1245 		job->data = condef_new (s);
1246 	}
1247 
1248 	/* Don't spend time on host name lookups */
1249 
1250 	if (job->hosts) {
1251 		host_list_free (job->hosts);
1252 		job->hosts = NULL;
1253 	}
1254 }
1255 
1256 
1257 
launch_callback(GtkWidget * widget,enum launch_mode mode)1258 static void launch_callback (GtkWidget *widget, enum launch_mode mode) {
1259 	int spectate = FALSE;
1260 	char *demo = NULL;
1261 	struct condef *con = NULL;
1262 
1263 	debug (6, "launc_callback() --");
1264 	if (stat_process || !cur_server ||
1265 			(games[cur_server->type].flags & GAME_CONNECT) == 0) {
1266 		return;
1267 	}
1268 	if (games[cur_server->type].config_is_valid &&
1269 			!(*games[cur_server->type].config_is_valid) (cur_server)) {
1270 		start_preferences_dialog (NULL, PREF_PAGE_GAMES + cur_server->type * 256);
1271 		return;
1272 	}
1273 
1274 	switch (mode) {
1275 
1276 		case LAUNCH_NORMAL:
1277 			break;
1278 
1279 		case LAUNCH_SPECTATE:
1280 			if ((cur_server->flags & SERVER_SPECTATE) == 0) {
1281 				return;
1282 			}
1283 
1284 			spectate = TRUE;
1285 			break;
1286 
1287 		case LAUNCH_RECORD:
1288 			if ((games[cur_server->type].flags & GAME_RECORD) == 0) {
1289 				return;
1290 			}
1291 
1292 			if ((games[cur_server->type].flags & GAME_SPECTATE) != 0) {
1293 				demo = enter_string_with_option_dialog (TRUE, _("Spectator"), &spectate, _("Demo name:"));
1294 			}
1295 			else {
1296 				demo = enter_string_dialog (TRUE, _("Demo name:"));
1297 			}
1298 
1299 			if (!demo) {
1300 				return;
1301 			}
1302 
1303 			break;
1304 
1305 	}
1306 
1307 	con = condef_new (cur_server);
1308 	con->demo = demo;
1309 	con->spectate = spectate;
1310 
1311 	stat_process = stat_job_create (NULL, NULL, server_list_prepend (NULL, cur_server), NULL);
1312 	stat_process->data = con;
1313 
1314 	stat_process->state_handlers = g_slist_prepend (
1315 			stat_process->state_handlers, stat_lists_state_handler);
1316 	stat_process->close_handlers = g_slist_prepend (
1317 			stat_process->close_handlers, stat_lists_close_handler);
1318 
1319 	stat_process->server_handlers = g_slist_append (
1320 			stat_process->server_handlers, launch_server_handler);
1321 
1322 	/* run last!!! */
1323 	stat_process->close_handlers = g_slist_append (
1324 			stat_process->close_handlers, launch_close_handler);
1325 
1326 	stat_start (stat_process);
1327 	set_widgets_sensitivity ();
1328 }
1329 
1330 static int server_clist_sort_mode = SORT_SERVER_PING;
1331 
server_clist_set_sort_mode(enum ssort_mode mode)1332 void server_clist_set_sort_mode(enum ssort_mode mode) {
1333 	server_clist_sort_mode = mode;
1334 }
1335 
server_clist_compare_func(GtkCList * clist,gconstpointer ptr1,gconstpointer ptr2)1336 static int server_clist_compare_func (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) {
1337 	int res, mode;
1338 	GtkCListRow *row1 = (GtkCListRow *) ptr1;
1339 	GtkCListRow *row2 = (GtkCListRow *) ptr2;
1340 	struct server *s1 = (struct server *) row1->data;
1341 	struct server *s2 = (struct server *) row2->data;
1342 	debug (7, "");
1343 
1344 	mode = server_clist_def.cols[clist->sort_column].sort_mode[server_clist_def.cols[clist->sort_column].current_sort_mode];
1345 	res = compare_servers (s1, s2, mode);
1346 
1347 	// fallback
1348 	if (res == 0 && mode != SORT_SERVER_PING) {
1349 		res = compare_servers(s1, s2, SORT_SERVER_PING);
1350 	}
1351 
1352 	return res;
1353 }
1354 
1355 
player_clist_compare_func(GtkCList * clist,gconstpointer ptr1,gconstpointer ptr2)1356 static int player_clist_compare_func (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) {
1357 	GtkCListRow *row1 = (GtkCListRow *) ptr1;
1358 	GtkCListRow *row2 = (GtkCListRow *) ptr2;
1359 	struct player *p1 = (struct player *) row1->data;
1360 	struct player *p2 = (struct player *) row2->data;
1361 
1362 	return compare_players (p1, p2, clist->sort_column);
1363 }
1364 
1365 
srvinf_clist_compare_func(GtkCList * clist,gconstpointer ptr1,gconstpointer ptr2)1366 static int srvinf_clist_compare_func (GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) {
1367 	GtkCListRow *row1 = (GtkCListRow *) ptr1;
1368 	GtkCListRow *row2 = (GtkCListRow *) ptr2;
1369 	const char **i1 = (const char **) row1->data;
1370 	const char **i2 = (const char **) row2->data;
1371 
1372 	return compare_srvinfo (i1, i2, clist->sort_column);
1373 }
1374 
1375 
update_source_callback(GtkWidget * widget,gpointer data)1376 void update_source_callback (GtkWidget *widget, gpointer data) {
1377 	GSList *masters = NULL;
1378 	GSList *servers = NULL;
1379 	GSList *uservers = NULL;
1380 
1381 	event_type=EVENT_UPDATE;
1382 
1383 	debug_increase_indent();
1384 	debug (6, "update_source_callback() -- ");
1385 	if (stat_process || !cur_source) {
1386 		return;
1387 	}
1388 
1389 	master_selection_to_lists (cur_source, &masters, &servers, &uservers);
1390 	if (masters || servers || uservers) {
1391 		stat_lists (masters, uservers, servers, NULL);
1392 	}
1393 	debug_decrease_indent();
1394 
1395 }
1396 
1397 
refresh_selected_callback(GtkWidget * widget,gpointer data)1398 static void refresh_selected_callback (GtkWidget *widget, gpointer data) {
1399 	GSList *list;
1400 
1401 	if (stat_process) {
1402 		debug(1,"nope");
1403 		return;
1404 	}
1405 
1406 	event_type=EVENT_REFRESH_SELECTED;
1407 
1408 	list = server_clist_selected_servers ();
1409 
1410 	if (list) {
1411 		stat_lists (NULL, NULL, list, NULL);
1412 	}
1413 }
1414 
1415 
refresh_callback(GtkWidget * widget,gpointer data)1416 static void refresh_callback (GtkWidget *widget, gpointer data) {
1417 	GSList *servers;
1418 	GSList *uservers;
1419 
1420 	if (stat_process) {
1421 		return;
1422 	}
1423 
1424 	event_type=EVENT_REFRESH;
1425 
1426 	debug (7, "refresh_callback() -- Get Server List");
1427 
1428 	servers = server_clist_all_servers ();
1429 	uservers = userver_list_copy (cur_userver_list);
1430 
1431 	debug (7, "refresh_callback() -- server list %lx", servers);
1432 
1433 	if (servers || uservers) {
1434 		stat_lists (NULL, uservers, servers, NULL);
1435 	}
1436 }
1437 
refresh_n_server(GtkWidget * button,gpointer * data)1438 void refresh_n_server (GtkWidget * button, gpointer *data) {
1439 	GSList *list;
1440 	gint number;
1441 
1442 	if (stat_process)
1443 		return;
1444 
1445 	event_type = EVENT_REFRESH;
1446 	number=GPOINTER_TO_INT(data);
1447 
1448 	list = server_clist_get_n_servers(number);
1449 
1450 	if (list) {
1451 		stat_lists(NULL, NULL, list, NULL);
1452 	}
1453 }
1454 
stop_callback(GtkWidget * widget,gpointer data)1455 void stop_callback (GtkWidget *widget, gpointer data) {
1456 
1457 	event_type = 0;		// To prevent sound from stopped action from playing
1458 
1459 	if (stat_process) {
1460 		stat_stop (stat_process);
1461 		stat_process = NULL;
1462 	}
1463 	redialserver = 0;	// Reset redialserver so prompt comes up next time
1464 	play_sound(sound_stop, 0);
1465 	event_type = 0;		// To prevent sound from stopped action from playing
1466 }
1467 
1468 
add_to_favorites_callback(GtkWidget * widget,gpointer data)1469 static void add_to_favorites_callback (GtkWidget *widget, gpointer data) {
1470 	GList *selected = server_clist->selection;
1471 	GSList *list;
1472 	GSList *tmp;
1473 	enum { buflen = 256 };
1474 	char buf[buflen];   /* if you change this, change the statement below */
1475 	int server_list_size;
1476 
1477 	debug (7, "add_to_favorites_callback() -- ");
1478 	if (stat_process || !selected) {
1479 		return;
1480 	}
1481 
1482 	list = server_clist_selected_servers ();
1483 	if (list) {
1484 		for (tmp = list; tmp; tmp = tmp->next) {
1485 			server_list_size = g_slist_length (favorites->servers);
1486 			favorites->servers =
1487 				server_list_append (favorites->servers, (struct server *) tmp->data);
1488 			if (server_list_size < g_slist_length (favorites->servers)){
1489 				snprintf(buf, buflen, "Added Server #%d: '%s'",
1490 						g_slist_length (favorites->servers),
1491 						((struct server *)tmp->data)->name);
1492 			} else {
1493 				snprintf(buf, buflen, "Server '%s' Already In Favorites",
1494 						((struct server *)tmp->data)->name);
1495 			}
1496 			print_status (main_status_bar, buf);
1497 
1498 		}
1499 		debug (7, "add_to_favorites_callback() -- Saving To Favorites");
1500 		save_favorites ();
1501 		server_list_free (list);
1502 	}
1503 }
1504 
1505 // add a server to favorites
new_server_to_favorites(struct stat_job * job,struct server * s)1506 static void new_server_to_favorites (struct stat_job *job, struct server *s) {
1507 	int row;
1508 
1509 	debug (6, "Server %lx, job %p", s, job);
1510 	favorites->servers = server_list_append (favorites->servers, s);
1511 	save_favorites ();
1512 
1513 	source_ctree_select_source (favorites);
1514 
1515 	if (cur_filter != 0) {
1516 		set_filters (0);    /* turn off filters */
1517 		if (job) {
1518 			job->need_redraw = FALSE;
1519 		}
1520 	}
1521 
1522 	row = gtk_clist_find_row_from_data (server_clist, s);
1523 	if (row >= 0) {
1524 		server_clist_select_one (row);
1525 		server_clist_selection_visible ();
1526 	}
1527 }
1528 
1529 
add_server_name_handler(struct stat_job * job,struct userver * us,enum dns_status status)1530 static void add_server_name_handler (struct stat_job *job, struct userver *us,
1531 		enum dns_status status) {
1532 	if (us->s) {
1533 		new_server_to_favorites (job, us->s);
1534 	}
1535 	else {
1536 		progress_bar_reset (main_progress_bar);
1537 		dialog_ok (NULL, _("Host %s not found"), us->hostname);
1538 	}
1539 }
1540 
1541 /** check specified address is valid, resolve hostname if needed, stat server,
1542  * finally call new_server_to_favorites
1543  * calls free(str)!!!
1544  */
prepare_new_server_to_favorites(enum server_type type,char * str,gboolean dolaunch)1545 static void prepare_new_server_to_favorites(enum server_type type, char* str, gboolean dolaunch) {
1546 	char *addr;
1547 	unsigned short port;
1548 	struct host *h;
1549 	struct server *s = NULL;
1550 	struct userver *us = NULL;
1551 
1552 	if (!str || !*str) {
1553 		return;
1554 	}
1555 
1556 	if (!parse_address (str, &addr, &port)) {
1557 		dialog_ok (NULL, _("\"%s\" is not valid host[:port] combination."), str);
1558 		g_free (str);
1559 		return;
1560 	}
1561 
1562 	g_free (str);
1563 
1564 	h = host_add (addr);
1565 	if (h) {    /* IP address */
1566 		host_ref (h);
1567 		s = server_add (h, port, type);
1568 		if (s) {
1569 			new_server_to_favorites (NULL, s);
1570 		}
1571 		host_unref (h);
1572 	}
1573 	else {  /* hostname */
1574 		us = userver_add (g_ascii_strdown(addr, -1), port, type);
1575 	}
1576 	g_free (addr);
1577 
1578 	if (s || us) {
1579 		stat_process = stat_job_create (NULL,
1580 				(us)? userver_list_add (NULL, us) : NULL,
1581 				(s)? server_list_prepend (NULL, s) : NULL,
1582 				NULL);
1583 
1584 		stat_process->state_handlers = g_slist_prepend (
1585 				stat_process->state_handlers, stat_lists_state_handler);
1586 		stat_process->close_handlers = g_slist_prepend (
1587 				stat_process->close_handlers, stat_lists_close_handler);
1588 
1589 		// stat_process->server_handlers = g_slist_append (stat_process->server_handlers, stat_lists_server_handler);
1590 
1591 		stat_process->name_handlers = g_slist_prepend (
1592 				stat_process->name_handlers, add_server_name_handler);
1593 
1594 		if (dolaunch) {
1595 			if (s) {
1596 				struct condef* con = condef_new (s);
1597 				stat_process->data = con;
1598 			}
1599 
1600 			stat_process->server_handlers = g_slist_append (
1601 					stat_process->server_handlers, launch_server_handler);
1602 
1603 			stat_process->close_handlers = g_slist_append (
1604 					stat_process->close_handlers, launch_close_handler);
1605 		}
1606 
1607 		stat_start (stat_process);
1608 		set_widgets_sensitivity ();
1609 	}
1610 }
1611 
add_server_callback(GtkWidget * widget,gpointer data)1612 static void add_server_callback (GtkWidget *widget, gpointer data) {
1613 	char *str = NULL;
1614 	enum server_type type  = UNKNOWN_SERVER;
1615 
1616 	if (stat_process) {
1617 		return;
1618 	}
1619 
1620 	str = add_server_dialog (&type, NULL);
1621 
1622 	if (!str) {
1623 		return;
1624 	}
1625 
1626 	prepare_new_server_to_favorites(type, str, FALSE);
1627 
1628 	return;
1629 }
1630 
del_server_callback(GtkWidget * widget,gpointer data)1631 static void del_server_callback (GtkWidget *widget, gpointer data) {
1632 	GSList *selected;
1633 	GSList *l, *c;
1634 	int is_favorites = 0;
1635 	int delete_from_all = 0;
1636 
1637 	debug(3, "--");
1638 
1639 	if (stat_process || !cur_source) {
1640 		return;
1641 	}
1642 
1643 	selected = server_clist_selected_servers();
1644 
1645 	if (!selected) {
1646 		return;
1647 	}
1648 
1649 	for (c = cur_source; c; c = c->next) {
1650 		struct master* m = (struct master *) c->data;
1651 
1652 		if (m == favorites) {
1653 			is_favorites = 1;
1654 		}
1655 
1656 		if (!delete_from_all && m->isgroup) {
1657 			delete_from_all = dialog_yesno (NULL, 1, _("Yes"), _("No"), _("Remove selected servers from all lists?"));
1658 		}
1659 	}
1660 
1661 	for (l = selected; l; l = l->next) {
1662 		struct server* s = (struct server*) l->data;
1663 
1664 		if (delete_from_all) {
1665 			server_remove_from_all(s);
1666 			master_remove_server(favorites, s);
1667 		}
1668 		else {
1669 			for (c = cur_source; c; c = c->next) {
1670 				struct master* m = (struct master *) c->data;
1671 
1672 				master_remove_server(m, s);
1673 			}
1674 		}
1675 	}
1676 
1677 	if (is_favorites) {
1678 		save_favorites();
1679 	}
1680 
1681 	g_slist_free(selected);
1682 
1683 	update_server_lists_from_selected_source ();
1684 	server_clist_build_filtered (cur_server_list, FALSE);
1685 }
1686 
1687 
copy_server_callback(GtkWidget * widget,gpointer data)1688 static void copy_server_callback (GtkWidget *widget, gpointer data) {
1689 	GList *selection = server_clist->selection;
1690 	struct server *s;
1691 	char buf[256];
1692 	int pos = 0;
1693 
1694 	gtk_editable_delete_text (selection_manager, 0, -1);
1695 
1696 	switch (g_list_length (selection)) {
1697 
1698 		case 0:
1699 			gtk_editable_select_region (selection_manager, 0, 0);
1700 			break;
1701 
1702 		default:
1703 			for (; selection; selection = selection->next) {
1704 				s = (struct server *) gtk_clist_get_row_data (
1705 						server_clist, GPOINTER_TO_INT(selection->data));
1706 				g_snprintf (buf, 256, "%s:%d%s", inet_ntoa (s->host->ip), s->port, selection->next?"\n":"");
1707 				gtk_editable_insert_text (selection_manager, buf, strlen (buf), &pos);
1708 			}
1709 			gtk_editable_select_region (selection_manager, 0, -1);
1710 			break;
1711 
1712 	}
1713 	gtk_editable_copy_clipboard(selection_manager);
1714 }
1715 
copy_server_info_callback(GtkWidget * widget,gpointer data)1716 static void copy_server_info_callback (GtkWidget *widget, gpointer data) {
1717 	GList *selection = GTK_CLIST(srvinf_ctree)->selection;
1718 	int pos = 0;
1719 
1720 	gtk_editable_delete_text (selection_manager, 0, -1);
1721 
1722 	if (!g_list_length (selection)) {
1723 		gtk_editable_select_region (selection_manager, 0, 0);
1724 	}
1725 	else {
1726 		for (; selection; selection = selection->next) {
1727 			GtkCTreeNode* node = GTK_CTREE_NODE(selection->data);
1728 			char* txt = NULL;
1729 
1730 			gtk_ctree_node_get_text(GTK_CTREE(srvinf_ctree), node, 1, &txt);
1731 			gtk_editable_insert_text (selection_manager, txt, strlen (txt), &pos);
1732 		}
1733 		gtk_editable_select_region (selection_manager, 0, -1);
1734 	}
1735 	gtk_editable_copy_clipboard(selection_manager);
1736 }
1737 
copy_text_to_clipboard(const char * text)1738 static void copy_text_to_clipboard(const char* text) {
1739 	int pos = 0;
1740 	gtk_editable_delete_text (selection_manager, 0, -1);
1741 	if (text && *text) {
1742 		gtk_editable_insert_text (selection_manager, text, strlen (text), &pos);
1743 	}
1744 	gtk_editable_select_region (selection_manager, 0, pos);
1745 	gtk_editable_copy_clipboard(selection_manager);
1746 }
1747 
copy_server_callback_plus(GtkWidget * widget,gpointer data)1748 static void copy_server_callback_plus (GtkWidget *widget, gpointer data) {
1749 	GList *selection = server_clist->selection;
1750 	struct server *s;
1751 	char buf[256];
1752 	int pos = 0;
1753 	unsigned players;
1754 
1755 	gtk_editable_delete_text (selection_manager, 0, -1);
1756 
1757 	switch (g_list_length (selection)) {
1758 
1759 		case 0:
1760 			gtk_editable_select_region (selection_manager, 0, 0);
1761 			break;
1762 
1763 		default:
1764 			for (; selection; selection = selection->next) {
1765 				s = (struct server *) gtk_clist_get_row_data (
1766 						server_clist, GPOINTER_TO_INT(selection->data));
1767 				players = s->curplayers;
1768 				if (serverlist_countbots && s->curbots <= players) {
1769 					players-=s->curbots;
1770 				}
1771 
1772 				g_snprintf (buf, 256, "%i  %s:%d  %s  %s  %i of %i%s", s->ping, inet_ntoa
1773 						(s->host->ip), s->port, s->name, s->map, players, s->maxplayers, selection->next?"\n":"");
1774 				gtk_editable_insert_text (selection_manager, buf, strlen (buf), &pos);
1775 			}
1776 			gtk_editable_select_region (selection_manager, 0, -1);
1777 			break;
1778 
1779 	}
1780 
1781 	gtk_editable_copy_clipboard(selection_manager);
1782 }
1783 
update_master_builtin_callback(GtkWidget * widget,gpointer data)1784 static void update_master_builtin_callback (GtkWidget *widget, gpointer data) {
1785 
1786 	update_master_list_builtin();
1787 
1788 }
1789 
update_master_gslist_callback(GtkWidget * widget,gpointer data)1790 static void update_master_gslist_callback (GtkWidget *widget, gpointer data) {
1791 	if (!have_gslist_installed()) {
1792 		// translator: %s == url
1793 		dialog_ok(NULL, _("For Gslist support you must install the 'gslist' program available from\n%s\n"
1794 					"Don't forget that you need to run 'gslist -u' before you can use it."), gslisthome);
1795 		copy_text_to_clipboard(gslisthome);
1796 		return;
1797 	}
1798 	update_master_gslist_builtin();
1799 }
1800 
add_master_callback(GtkWidget * widget,gpointer data)1801 static void add_master_callback (GtkWidget *widget, gpointer data) {
1802 	struct master *m;
1803 
1804 	if (stat_process) {
1805 		return;
1806 	}
1807 
1808 	m = add_master_dialog(NULL);
1809 
1810 	if (m) {
1811 		source_ctree_add_master (source_ctree, m);
1812 		source_ctree_select_source (m);
1813 	}
1814 }
1815 
1816 // does only work with one master selected
edit_master_callback(GtkWidget * widget,gpointer data)1817 static void edit_master_callback (GtkWidget *widget, gpointer data) {
1818 	struct master *master_to_edit, *master_to_add;
1819 
1820 	if (!cur_source) {
1821 		return;
1822 	}
1823 
1824 	master_to_edit = (struct master *) cur_source->data;
1825 	source_ctree_select_source (master_to_edit);
1826 	master_to_add = add_master_dialog(master_to_edit);
1827 	if (master_to_add) {
1828 		source_ctree_add_master (source_ctree, master_to_add);
1829 		source_ctree_select_source (master_to_add);
1830 	}
1831 }
1832 
del_master_callback(GtkWidget * widget,gpointer data)1833 static void del_master_callback (GtkWidget *widget, gpointer data) {
1834 	struct master *m;
1835 	GSList *masters = NULL;
1836 	char *master_names = NULL;
1837 	GSList *list;
1838 	int delete;
1839 	char *s1;
1840 	char *s2;
1841 
1842 	if (stat_process) {
1843 		return;
1844 	}
1845 
1846 	for (list = cur_source; list; list = list->next) {
1847 		m = (struct master *) list->data;
1848 		if (m != favorites && !m->isgroup) {
1849 
1850 			masters = g_slist_append (masters, m);
1851 			s1 = g_strdup_printf ("%s (%s)", m->name, games[m->type].name);
1852 
1853 			if (!master_names) {
1854 				master_names = s1;
1855 			}
1856 			else {
1857 				s2= master_names;
1858 				master_names = g_strconcat (s2, "\n", s1, NULL);
1859 				g_free (s1);
1860 				g_free (s2);
1861 			}
1862 
1863 		}
1864 	}
1865 
1866 	if (!masters) {
1867 		dialog_ok(NULL,_("You have to select the server you want to delete"));
1868 		return;
1869 	}
1870 
1871 	// FIXME: plural
1872 	delete = dialog_yesno (NULL, 1, _("Delete"), _("Cancel"),
1873 			_("Master%s to delete:\n\n%s"),
1874 			(g_slist_length (masters) > 1)? "s" : "",
1875 			master_names);
1876 
1877 	if (delete) {
1878 		for (list = masters; list; list = list->next) {
1879 			m = (struct master *) list->data;
1880 			source_ctree_delete_master (source_ctree, m);
1881 			free_master (m);
1882 		}
1883 	}
1884 
1885 	g_free (master_names);
1886 	g_slist_free (masters);
1887 }
1888 
1889 
find_player_callback(GtkWidget * widget,int find_next)1890 static void find_player_callback (GtkWidget *widget, int find_next) {
1891 	char *pattern;
1892 
1893 	if (find_next || find_player_dialog ()) {
1894 		if (!psearch_data_is_empty ()) {
1895 			pattern = psearch_lookup_pattern ();
1896 			print_status (main_status_bar, _("Find Player: %s"), pattern);
1897 			g_free (pattern);
1898 
1899 			find_player (find_next);
1900 		}
1901 	}
1902 }
1903 
1904 
show_hostnames_callback(GtkWidget * widget,gpointer data)1905 static void show_hostnames_callback (GtkWidget *widget, gpointer data) {
1906 
1907 	if (stat_process || !server_clist || server_clist->rows == 0) {
1908 		return;
1909 	}
1910 
1911 	if (GTK_CHECK_MENU_ITEM (view_hostnames_menu_item)->active != show_hostnames) {
1912 		show_hostnames = GTK_CHECK_MENU_ITEM (view_hostnames_menu_item)->active;
1913 		server_clist_redraw ();
1914 		config_set_bool ("/" CONFIG_FILE "/Appearance/show hostnames",  show_hostnames);
1915 	}
1916 }
1917 
1918 
show_default_port_callback(GtkWidget * widget,gpointer data)1919 static void show_default_port_callback (GtkWidget *widget, gpointer data) {
1920 
1921 	if (stat_process || !server_clist || server_clist->rows == 0) {
1922 		return;
1923 	}
1924 
1925 	if (GTK_CHECK_MENU_ITEM (view_defport_menu_item)->active != show_default_port) {
1926 		show_default_port = GTK_CHECK_MENU_ITEM (view_defport_menu_item)->active;
1927 		server_clist_redraw ();
1928 		config_set_bool ("/" CONFIG_FILE "/Appearance/show default port", show_default_port);
1929 	}
1930 }
1931 
1932 
resolve_callback(GtkWidget * widget,gpointer data)1933 static void resolve_callback (GtkWidget *widget, gpointer data) {
1934 	GSList *selected;
1935 	GSList *hosts;
1936 	struct server *s;
1937 
1938 	debug (7, "resolve_callback() --");
1939 	if (stat_process) {
1940 		return;
1941 	}
1942 
1943 	if (!show_hostnames) {
1944 		gtk_check_menu_item_set_active (
1945 				GTK_CHECK_MENU_ITEM (view_hostnames_menu_item), TRUE);
1946 	}
1947 
1948 	selected = server_clist_selected_servers ();
1949 	if (!selected) {
1950 		return;
1951 	}
1952 
1953 	if (selected->next) {
1954 		hosts = merge_hosts_to_resolve (NULL, selected);
1955 	}
1956 	else {
1957 
1958 		/* always resolve if only one host is asked to */
1959 
1960 		s = (struct server *) selected->data;
1961 		hosts = host_list_add (NULL, s->host);
1962 	}
1963 
1964 	server_list_free (selected);
1965 
1966 	stat_lists (NULL, NULL, NULL, hosts);
1967 }
1968 
1969 
properties_callback(GtkWidget * widget,gpointer data)1970 static void properties_callback (GtkWidget *widget, gpointer data) {
1971 
1972 	if (stat_process) {
1973 		return;
1974 	}
1975 
1976 	if (cur_server) {
1977 		properties_dialog (cur_server);
1978 		set_widgets_sensitivity ();
1979 	}
1980 }
1981 
1982 #if 0
1983 static void cancelredial_callback (GtkWidget *widget, gpointer data) {
1984 
1985 	if (stat_process) {
1986 		return;
1987 	}
1988 
1989 	redialserver = 0;
1990 	print_status (main_status_bar, _("Done."));
1991 	progress_bar_reset (main_progress_bar);
1992 
1993 }
1994 #endif
1995 
rcon_callback(GtkWidget * widget,gpointer data)1996 static void rcon_callback (GtkWidget *widget, gpointer data) {
1997 	struct server_props *sp;
1998 	char *passwd = NULL;
1999 	int save = 0;
2000 
2001 	if (stat_process || !cur_server ||
2002 			(games[cur_server->type].flags & GAME_RCON) == 0) {
2003 		return;
2004 	}
2005 
2006 	sp = properties (cur_server);
2007 
2008 	if (!sp || !sp->rcon_password) {
2009 		passwd = enter_string_with_option_dialog (FALSE,
2010 				_("Save Password"), &save, _("Server Password:"));
2011 
2012 		if (!passwd)    /* canceled */
2013 			return;
2014 
2015 		if (save) {
2016 			if (!sp) {
2017 				sp = properties_new (cur_server->host, cur_server->port);
2018 			}
2019 			sp->rcon_password = passwd;
2020 			props_save ();
2021 			passwd = NULL;
2022 		}
2023 	}
2024 
2025 	rcon_dialog (cur_server, (passwd)? passwd : sp->rcon_password);
2026 
2027 	if (passwd) {
2028 		g_free (passwd);
2029 	}
2030 }
2031 
2032 
server_clist_select_callback(GtkWidget * widget,int row,int column,GdkEvent * event,GtkWidget * button)2033 static void server_clist_select_callback (GtkWidget *widget, int row,
2034 		int column, GdkEvent *event, GtkWidget *button) {
2035 	GdkEventButton *bevent = (GdkEventButton *) event;
2036 	debug (7, "server_clist_select_callback() -- Row %d", row);
2037 	server_clist_sync_selection ();
2038 
2039 	if (bevent && bevent->type == GDK_2BUTTON_PRESS && bevent->button == 1 &&
2040 			!((column == 6) && cur_server && (games[cur_server->type].get_mapshot))) // not for map preview
2041 	{
2042 		launch_callback (NULL, LAUNCH_NORMAL);
2043 	}
2044 }
2045 
2046 
server_clist_unselect_callback(GtkWidget * widget,int row,int column,GdkEvent * event,GtkWidget * button)2047 static void server_clist_unselect_callback (GtkWidget *widget, int row,
2048 		int column, GdkEvent *event, GtkWidget *button) {
2049 	debug (7, "server_clist_uselect_callback() -- Row %d", row);
2050 	server_clist_sync_selection ();
2051 }
2052 
2053 
2054 /* Deal with key-presses in the server pane */
server_clist_keypress_callback(GtkWidget * widget,GdkEventKey * event)2055 static gboolean server_clist_keypress_callback (GtkWidget *widget, GdkEventKey *event) {
2056 
2057 	debug (7, "server_clist_keypress_callback() -- CLIST Key %x", event->keyval);
2058 	if (event->keyval == GDK_Delete) {
2059 		del_server_callback(widget, event);
2060 		return TRUE;
2061 	} else if (event->keyval == GDK_Insert) {
2062 		if (event->state & GDK_SHIFT_MASK){
2063 			add_to_favorites_callback(widget, event);
2064 		} else {
2065 			add_server_callback (widget, event);
2066 		}
2067 		return TRUE;
2068 	} else if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
2069 		launch_callback(widget, LAUNCH_NORMAL);
2070 		return TRUE;
2071 	}
2072 	return FALSE;
2073 }
2074 
source_ctree_event_callback(GtkWidget * widget,GdkEvent * event)2075 static int source_ctree_event_callback (GtkWidget *widget, GdkEvent *event) {
2076 	GdkEventButton *bevent = (GdkEventButton *) event;
2077 	GList *selection;
2078 	int row;
2079 	GtkCTreeNode *node, *node_under_mouse;
2080 	int node_is_in_selection = 0;
2081 
2082 	if (event->type == GDK_BUTTON_PRESS &&
2083 			bevent->window == GTK_CLIST(source_ctree)->clist_window) {
2084 
2085 		switch (bevent->button) {
2086 
2087 			case 3:
2088 				// lets see which row the cursor is on
2089 				if (gtk_clist_get_selection_info (GTK_CLIST(source_ctree),
2090 							bevent->x, bevent->y, &row, NULL)) {
2091 					// list of selected items
2092 					selection = GTK_CLIST(source_ctree)->selection;
2093 					// XXX: what is the first part of the && good for?
2094 					if (!g_list_find (selection, GINT_TO_POINTER(row)) &&
2095 							(bevent->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0) {
2096 						node_under_mouse = gtk_ctree_node_nth(GTK_CTREE (source_ctree),row);
2097 						if (node_under_mouse) {
2098 							// go through all selected masters and search if the one under the
2099 							// cursor is among them
2100 							while (selection) {
2101 								node = GTK_CTREE_NODE(selection->data);
2102 								if (node == node_under_mouse) {
2103 									node_is_in_selection = 1;
2104 									break;
2105 								}
2106 								selection = selection->next;
2107 							}
2108 
2109 							// clear selection and only select the one under the curser
2110 							if (!node_is_in_selection) {
2111 								gtk_ctree_unselect_recursive(GTK_CTREE(source_ctree),NULL);
2112 								gtk_ctree_select (GTK_CTREE (source_ctree), node_under_mouse);
2113 							}
2114 						}
2115 					}
2116 
2117 				}
2118 
2119 				gtk_menu_popup (GTK_MENU (source_menu), NULL, NULL, NULL, NULL,
2120 						bevent->button, bevent->time);
2121 				return TRUE;
2122 
2123 			default:
2124 				return FALSE;
2125 		}
2126 
2127 	}
2128 	return FALSE;
2129 }
2130 
2131 static GtkWidget *server_mapshot_popup = NULL;
2132 static GtkWidget *server_mapshot_popup_pixmap = NULL;
2133 
server_mapshot_preview_popup_show(guchar * imagedata,size_t len,int x,int y)2134 static void server_mapshot_preview_popup_show (guchar *imagedata, size_t len, int x, int y) {
2135 	GtkWidget *frame;
2136 	int win_x, win_y, scr_w, scr_h;
2137 	guint w = 0, h = 0;
2138 	GdkPixmap *pix = NULL;
2139 	GdkBitmap *mask = NULL;
2140 
2141 	renderMemToGtkPixmap(imagedata,len,&pix,&mask,&w,&h, 64);
2142 
2143 	if (!pix || !w || !h) {
2144 		if (pix) gdk_pixmap_unref(pix);
2145 		if (mask) gdk_bitmap_unref(mask);
2146 		pix=stop_pix.pix;
2147 		mask=stop_pix.mask;
2148 	}
2149 
2150 	if (!server_mapshot_popup) {
2151 		server_mapshot_popup = gtk_window_new (GTK_WINDOW_POPUP);
2152 		gtk_window_set_policy (GTK_WINDOW (server_mapshot_popup), FALSE, FALSE, TRUE);
2153 
2154 		frame = gtk_frame_new (NULL);
2155 		gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
2156 		gtk_container_add (GTK_CONTAINER (server_mapshot_popup), frame);
2157 		gtk_widget_show (frame);
2158 
2159 		server_mapshot_popup_pixmap = gtk_pixmap_new(pix,mask);
2160 		gtk_container_add (GTK_CONTAINER (frame), server_mapshot_popup_pixmap);
2161 		//    gtk_preview_size (GTK_PREVIEW (pixmap), 320, 200);
2162 		gtk_widget_show (server_mapshot_popup_pixmap);
2163 	}
2164 	else {
2165 		gtk_widget_hide (server_mapshot_popup);
2166 		gtk_pixmap_set(GTK_PIXMAP(server_mapshot_popup_pixmap),pix,mask);
2167 	}
2168 
2169 	gdk_window_get_origin (server_clist->clist_window, &win_x, &win_y);
2170 	x += win_x;
2171 	y += win_y;
2172 	scr_w = gdk_screen_width ();
2173 	scr_h = gdk_screen_height ();
2174 	x = (x + w > scr_w)? scr_w - w : x;
2175 	y = (y + h > scr_h)? scr_h - h : y;
2176 
2177 	//  debug(0,"%d %d %d %d %d %d",scr_w,scr_h,x,y,w,h);
2178 
2179 	gtk_widget_set_uposition (server_mapshot_popup, x, y);
2180 	gtk_widget_show(server_mapshot_popup);
2181 }
2182 
server_clist_event_callback(GtkWidget * widget,GdkEvent * event)2183 static int server_clist_event_callback (GtkWidget *widget, GdkEvent *event) {
2184 	GdkEventButton *bevent = (GdkEventButton *) event;
2185 	GList *selection;
2186 	int row, column;
2187 
2188 	debug (7, "server_clist_event_callback() -- ");
2189 	if (event->type == GDK_BUTTON_PRESS &&
2190 			bevent->window == server_clist->clist_window) {
2191 
2192 		switch (bevent->button) {
2193 			case 1:
2194 				if (gtk_clist_get_selection_info (server_clist,
2195 							bevent->x, bevent->y, &row, &column)) {
2196 					server_clist_select_one (row);
2197 					if ((column == 6) && cur_server && (games[cur_server->type].get_mapshot)) {
2198 						size_t buflen;
2199 						guchar* buf = NULL;
2200 
2201 						buflen = games[cur_server->type].get_mapshot(cur_server,&buf);
2202 
2203 						gdk_pointer_grab (server_clist->clist_window, FALSE,
2204 								GDK_POINTER_MOTION_HINT_MASK |
2205 								GDK_BUTTON1_MOTION_MASK |
2206 								GDK_BUTTON_RELEASE_MASK,
2207 								NULL, NULL, bevent->time);
2208 
2209 						server_mapshot_preview_popup_show (buf, buflen, bevent->x, bevent->y);
2210 
2211 						g_free (buf);
2212 						return TRUE;
2213 					}
2214 				}
2215 				break;
2216 
2217 			case 2:
2218 				if (gtk_clist_get_selection_info (server_clist, bevent->x, bevent->y, &row, NULL)) {
2219 					server_clist_select_one (row);
2220 					stat_one_server (cur_server);
2221 				}
2222 				return TRUE;
2223 
2224 			case 3:
2225 				if (gtk_clist_get_selection_info (server_clist, bevent->x, bevent->y, &row, NULL)) {
2226 					selection = server_clist->selection;
2227 					if (!g_list_find (selection, GINT_TO_POINTER(row)) && (bevent->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0) {
2228 						server_clist_select_one (row);
2229 					}
2230 				}
2231 				gtk_menu_popup (GTK_MENU (server_menu), NULL, NULL, NULL, NULL,
2232 						bevent->button, bevent->time);
2233 				return TRUE;
2234 
2235 			default:
2236 				return FALSE;
2237 		}
2238 
2239 	}
2240 
2241 	if (event->type == GDK_BUTTON_RELEASE &&
2242 			bevent->window == server_clist->clist_window) {
2243 		if (server_mapshot_popup) {
2244 			gdk_pointer_ungrab (bevent->time);
2245 			gtk_widget_hide (server_mapshot_popup);
2246 		}
2247 	}
2248 
2249 	return FALSE;
2250 }
2251 
server_info_clist_event_callback(GtkWidget * widget,GdkEvent * event)2252 static int server_info_clist_event_callback (GtkWidget *widget, GdkEvent *event) {
2253 	GdkEventButton *bevent = (GdkEventButton *) event;
2254 	GList *selection;
2255 	GtkCTreeNode *node, *node_under_mouse;
2256 	int row = -1;
2257 	int node_is_in_selection = 0;
2258 
2259 	if (event->type == GDK_BUTTON_PRESS
2260 			&& bevent->window == GTK_CLIST(srvinf_ctree)->clist_window
2261 			&& bevent->button == 3) {
2262 
2263 		if (gtk_clist_get_selection_info (GTK_CLIST(srvinf_ctree), bevent->x, bevent->y, &row, NULL)) {
2264 
2265 			selection = GTK_CLIST(srvinf_ctree)->selection;
2266 			if (!g_list_find (selection, GINT_TO_POINTER(row)) && (bevent->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0) {
2267 				node_under_mouse = gtk_ctree_node_nth(GTK_CTREE (srvinf_ctree),row);
2268 				if (node_under_mouse) {
2269 					// go through all selected masters and search if the one under the
2270 					// cursor is among them
2271 					while (selection) {
2272 						node = GTK_CTREE_NODE(selection->data);
2273 						if (node == node_under_mouse) {
2274 							node_is_in_selection = 1;
2275 							break;
2276 						}
2277 						selection = selection->next;
2278 					}
2279 
2280 					// clear selection and only select the one under the curser
2281 					if (!node_is_in_selection) {
2282 						gtk_ctree_unselect_recursive(GTK_CTREE(srvinf_ctree),NULL);
2283 						gtk_ctree_select (GTK_CTREE (srvinf_ctree), node_under_mouse);
2284 					}
2285 				}
2286 			}
2287 		}
2288 		gtk_menu_popup (GTK_MENU (server_info_menu), NULL, NULL, NULL, NULL,
2289 				bevent->button, bevent->time);
2290 
2291 		return TRUE;
2292 	}
2293 
2294 	return FALSE;
2295 }
2296 
2297 
source_selection_changed(void)2298 static void source_selection_changed (void) {
2299 	GList *selection = GTK_CLIST (source_ctree)->selection;
2300 	GtkCTreeNode *node;
2301 	struct master *m;
2302 
2303 	debug (6, "souce_selection_changed() --");
2304 	if (cur_source) {
2305 		g_slist_free (cur_source);
2306 		cur_source = NULL;
2307 	}
2308 
2309 	while (selection) {
2310 		node = (GtkCTreeNode *) selection->data;
2311 		m = (struct master *) gtk_ctree_node_get_row_data (
2312 				GTK_CTREE (source_ctree), node);
2313 		cur_source = g_slist_append (cur_source, m);
2314 		selection = selection->next;
2315 	}
2316 
2317 	update_server_lists_from_selected_source ();
2318 	server_clist_set_list (cur_server_list);
2319 
2320 	reset_main_status_bar();
2321 }
2322 
2323 
source_ctree_selection_changed_callback(GtkWidget * widget,int row,int column,GdkEvent * event,GtkWidget * button)2324 static void source_ctree_selection_changed_callback (GtkWidget *widget,
2325 		int row, int column, GdkEvent *event, GtkWidget *button) {
2326 	debug(6,"source_ctree_selection_changed_callback(%p,%d,%d,%p,%p)",widget,row,column,event,button);
2327 	source_selection_changed ();
2328 }
2329 
source_selection_clear_master_servers(void)2330 static void source_selection_clear_master_servers (void) {
2331 	struct master *m;
2332 	GSList* source = NULL;
2333 
2334 	for (source = cur_source; source; source=source->next) {
2335 		m = (struct master *) source->data;
2336 
2337 		if (m == favorites || m->isgroup) {
2338 			continue;
2339 		}
2340 
2341 		server_list_free(m->servers);
2342 		m->servers = NULL;
2343 	}
2344 
2345 	update_server_lists_from_selected_source ();
2346 	server_clist_set_list (cur_server_list);
2347 
2348 	reset_main_status_bar();
2349 }
2350 
clear_master_servers_callback(GtkWidget * widget,int row,int column,GdkEvent * event,GtkWidget * button)2351 static void clear_master_servers_callback (GtkWidget *widget,
2352 		int row, int column, GdkEvent *event, GtkWidget *button) {
2353 	source_selection_clear_master_servers ();
2354 }
2355 
add_to_player_filter_callback(GtkWidget * widget,unsigned mask)2356 static void add_to_player_filter_callback (GtkWidget *widget, unsigned mask) {
2357 	GList *selection = player_clist->selection;
2358 	struct player *p;
2359 	int row;
2360 
2361 	if (!selection || !cur_server || stat_process) {
2362 		return;
2363 	}
2364 
2365 	row = GPOINTER_TO_INT(selection->data);
2366 	p = (struct player *) gtk_clist_get_row_data (player_clist, row);
2367 
2368 	if (player_filter_add_player (p->name, mask)) {
2369 		server_clist_build_filtered (cur_server_list, TRUE);
2370 		player_clist_redraw ();
2371 	}
2372 }
2373 
2374 
player_skin_preview_popup_show(guchar * skin,int top,int bottom,int x,int y)2375 static void player_skin_preview_popup_show (guchar *skin,
2376 		int top, int bottom, int x, int y) {
2377 	GtkWidget *frame;
2378 	int win_x, win_y, scr_w, scr_h;
2379 
2380 	if (!player_skin_popup) {
2381 		player_skin_popup = gtk_window_new (GTK_WINDOW_POPUP);
2382 		gtk_window_set_policy (GTK_WINDOW (player_skin_popup), FALSE, FALSE, TRUE);
2383 
2384 		frame = gtk_frame_new (NULL);
2385 		gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
2386 		gtk_container_add (GTK_CONTAINER (player_skin_popup), frame);
2387 		gtk_widget_show (frame);
2388 
2389 		player_skin_popup_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
2390 		gtk_container_add (GTK_CONTAINER (frame), player_skin_popup_preview);
2391 		gtk_preview_size (GTK_PREVIEW (player_skin_popup_preview), 320, 200);
2392 		gtk_widget_show (player_skin_popup_preview);
2393 	}
2394 	else {
2395 		gtk_widget_hide (player_skin_popup);
2396 	}
2397 
2398 	gdk_window_get_origin (player_clist->clist_window, &win_x, &win_y);
2399 	x += win_x;
2400 	y += win_y;
2401 	scr_w = gdk_screen_width ();
2402 	scr_h = gdk_screen_height ();
2403 	x = (x + 320 > scr_w)? scr_w - 320 : x;
2404 	y = (y + 200 > scr_h)? scr_h - 200 : y;
2405 
2406 	gtk_widget_set_uposition (player_skin_popup, x, y);
2407 	gtk_widget_show(player_skin_popup);
2408 
2409 	draw_qw_skin (player_skin_popup_preview, skin, top, bottom);
2410 }
2411 
2412 
player_clist_event_callback(GtkWidget * widget,GdkEvent * event)2413 static int player_clist_event_callback (GtkWidget *widget, GdkEvent *event) {
2414 	GdkEventButton *bevent = (GdkEventButton *) event;
2415 	guchar *skindata;
2416 	int row, column;
2417 	struct player *p;
2418 
2419 	switch (event->type) {
2420 
2421 		case GDK_BUTTON_PRESS:
2422 			if (bevent->window == player_clist->clist_window) {
2423 				if (gtk_clist_get_selection_info (player_clist, bevent->x, bevent->y, &row, &column)) {
2424 					if (row >= 0 && row < g_slist_length (cur_server->players)) {
2425 
2426 						if ((column == 2 || column == 3) && cur_server &&
2427 								(games[cur_server->type].flags & GAME_QUAKE1_SKIN) != 0) {
2428 
2429 							p = (struct player *) gtk_clist_get_row_data (player_clist, row);
2430 
2431 							skindata = get_qw_skin (p->skin, games[QW_SERVER].real_dir);
2432 
2433 							gdk_pointer_grab (player_clist->clist_window, FALSE,
2434 									GDK_POINTER_MOTION_HINT_MASK |
2435 									GDK_BUTTON1_MOTION_MASK |
2436 									GDK_BUTTON_RELEASE_MASK,
2437 									NULL, NULL, bevent->time);
2438 
2439 							player_skin_preview_popup_show (skindata, p->shirt, p->pants, bevent->x, bevent->y);
2440 							if (skindata) {
2441 								g_free (skindata);
2442 							}
2443 
2444 							return TRUE;
2445 
2446 						}
2447 						else {
2448 							if (bevent->button == 3) {
2449 								gtk_clist_select_row (player_clist, row, column);
2450 								gtk_menu_popup (GTK_MENU (player_menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
2451 								return TRUE;
2452 							}
2453 						}
2454 
2455 					}
2456 				}
2457 			}
2458 			break;
2459 
2460 		case GDK_2BUTTON_PRESS:
2461 		case GDK_3BUTTON_PRESS:
2462 			return TRUE;
2463 
2464 		case GDK_BUTTON_RELEASE:
2465 			if (player_skin_popup) {
2466 				gdk_pointer_ungrab (bevent->time);
2467 				gtk_widget_hide (player_skin_popup);
2468 			}
2469 			break;
2470 
2471 		default:
2472 			break;
2473 	}
2474 
2475 	return FALSE;
2476 }
2477 
2478 
statistics_callback(GtkWidget * widget,gpointer data)2479 static void statistics_callback (GtkWidget *widget, gpointer data) {
2480 
2481 	if (stat_process) {
2482 		return;
2483 	}
2484 
2485 	statistics_dialog ();
2486 }
2487 
2488 
2489 
2490 struct __menuitem {
2491 	char *label;
2492 	char accel_key;
2493 	int accel_mods;
2494 	GtkWidget **widget;
2495 	GtkSignalFunc	callback;
2496 	gpointer user_data;
2497 };
2498 
2499 
2500 
2501 
2502 static const struct menuitem srvopt_menu_items[] = {
2503 	{
2504 		MENU_ITEM,
2505 		N_("Connect"),
2506 		0,
2507 		0,
2508 		GTK_SIGNAL_FUNC (launch_callback),
2509 		(gpointer) LAUNCH_NORMAL,
2510 		&connect_menu_item
2511 	},
2512 	{
2513 		MENU_ITEM,
2514 		N_("Observe"),
2515 		0,
2516 		0,
2517 		GTK_SIGNAL_FUNC (launch_callback),
2518 		(gpointer) LAUNCH_SPECTATE,
2519 		&observe_menu_item
2520 	},
2521 	{
2522 		MENU_ITEM,
2523 		N_("Record Demo"),
2524 		0,
2525 		0,
2526 		GTK_SIGNAL_FUNC (launch_callback),
2527 		(gpointer) LAUNCH_RECORD,
2528 		&record_menu_item
2529 	},
2530 	/*
2531 	{
2532 		MENU_ITEM,
2533 		N_("Cancel Redial"),
2534 		0,
2535 		0,
2536 		GTK_SIGNAL_FUNC (cancelredial_callback),
2537 		NULL,
2538 		&cancel_redial_menu_item
2539 	},
2540 	*/
2541 	{
2542 		MENU_SEPARATOR,
2543 		NULL,
2544 		0,
2545 		0,
2546 		NULL,
2547 		NULL,
2548 		NULL
2549 	},
2550 	{
2551 		MENU_ITEM,
2552 		N_("Add new Server"),
2553 		0,
2554 		0,
2555 		GTK_SIGNAL_FUNC (add_server_callback),
2556 		NULL,
2557 		&add_menu_item
2558 	},
2559 	{
2560 		MENU_ITEM,
2561 		N_("Add to Favorites"),
2562 		0,
2563 		0,
2564 		GTK_SIGNAL_FUNC (add_to_favorites_callback),
2565 		NULL,
2566 		&favadd_menu_item
2567 	},
2568 	{
2569 		MENU_ITEM,
2570 		N_("Remove"),
2571 		0,
2572 		0,
2573 		GTK_SIGNAL_FUNC (del_server_callback),
2574 		NULL,
2575 		&delete_menu_item
2576 	},
2577 	{
2578 		MENU_ITEM,
2579 		N_("Copy"),
2580 		0,
2581 		0,
2582 		GTK_SIGNAL_FUNC (copy_server_callback),
2583 		NULL,
2584 		NULL
2585 	},
2586 	{
2587 		MENU_ITEM,
2588 		N_("Copy+"),
2589 		0,
2590 		0,
2591 		GTK_SIGNAL_FUNC (copy_server_callback_plus),
2592 		NULL,
2593 		NULL
2594 	},
2595 	{	MENU_SEPARATOR,
2596 		NULL,
2597 		0,
2598 		0,
2599 		NULL,
2600 		NULL,
2601 		NULL
2602 	},
2603 	{
2604 		MENU_ITEM,
2605 		N_("Refresh"),
2606 		0,
2607 		0,
2608 		GTK_SIGNAL_FUNC (refresh_callback),
2609 		NULL,
2610 		&refresh_menu_item
2611 	},
2612 	{
2613 		MENU_ITEM,
2614 		N_("Refresh Selected"),
2615 		0,
2616 		0,
2617 		GTK_SIGNAL_FUNC (refresh_selected_callback),
2618 		NULL,
2619 		&refrsel_menu_item
2620 	},
2621 	{
2622 		MENU_SEPARATOR,
2623 		NULL,
2624 		0,
2625 		0,
2626 		NULL,
2627 		NULL,
2628 		NULL
2629 	},
2630 	{
2631 		MENU_ITEM,
2632 		N_("DNS Lookup"),
2633 		0,
2634 		0,
2635 		GTK_SIGNAL_FUNC (resolve_callback),
2636 		NULL,
2637 		&resolve_menu_item
2638 	},
2639 	{
2640 		MENU_SEPARATOR,
2641 		NULL,
2642 		0,
2643 		0,
2644 		NULL,
2645 		NULL,
2646 		NULL
2647 	},
2648 	{
2649 		MENU_ITEM,
2650 		N_("RCon"),
2651 		0,
2652 		0,
2653 		GTK_SIGNAL_FUNC (rcon_callback),
2654 		NULL,
2655 		&rcon_menu_item
2656 	},
2657 	{
2658 		MENU_ITEM,
2659 		N_("Properties"),
2660 		0,
2661 		0,
2662 		GTK_SIGNAL_FUNC (properties_callback),
2663 		NULL,
2664 		&properties_menu_item
2665 	},
2666 	{
2667 		MENU_END,
2668 		NULL,
2669 		0,
2670 		0,
2671 		NULL,
2672 		NULL,
2673 		NULL
2674 	}
2675 };
2676 
2677 static const struct menuitem srvinfo_menu_items[] = {
2678 	{
2679 		MENU_ITEM,
2680 		N_("Copy"),
2681 		0,
2682 		0,
2683 		GTK_SIGNAL_FUNC (copy_server_info_callback), NULL,
2684 		NULL
2685 	},
2686 	{
2687 		MENU_END,
2688 		NULL,
2689 		0,
2690 		0,
2691 		NULL,
2692 		NULL,
2693 		NULL
2694 	}
2695 };
2696 static const struct menuitem file_menu_items[] = {
2697 	{
2698 		MENU_ITEM,
2699 		N_("_Statistics"),
2700 		0,
2701 		0,
2702 		GTK_SIGNAL_FUNC (statistics_callback),
2703 		NULL,
2704 		&file_statistics_menu_item
2705 	},
2706 	{
2707 		MENU_SEPARATOR,
2708 		NULL,
2709 		0,
2710 		0,
2711 		NULL,
2712 		NULL,
2713 		NULL
2714 	},
2715 	{
2716 		MENU_ITEM,
2717 		N_("_Exit"),
2718 		'Q',
2719 		GDK_CONTROL_MASK,
2720 		NULL,
2721 		NULL,
2722 		&file_quit_menu_item
2723 	},
2724 	{
2725 		MENU_END,
2726 		NULL,
2727 		0,
2728 		0,
2729 		NULL,
2730 		NULL,
2731 		NULL
2732 	}
2733 };
2734 
2735 // appears on right click on a master server
2736 static const struct menuitem source_ctree_popup_menu[] = {
2737 	{
2738 		MENU_ITEM,
2739 		N_("Add _Master"),
2740 		'M',
2741 		GDK_CONTROL_MASK,
2742 		GTK_SIGNAL_FUNC (add_master_callback),
2743 		NULL,
2744 		&source_add_master_menu_item
2745 	},
2746 	{
2747 		MENU_ITEM,
2748 		N_("_Rename Master"),
2749 		0,
2750 		0,
2751 		GTK_SIGNAL_FUNC (edit_master_callback),
2752 		NULL,
2753 		&source_edit_master_menu_item
2754 	},
2755 	{
2756 		MENU_ITEM,
2757 		N_("D_elete Master"),
2758 		0,	0,
2759 		GTK_SIGNAL_FUNC (del_master_callback),
2760 		NULL,
2761 		&source_delete_master_menu_item
2762 	},
2763 	{
2764 		MENU_ITEM,
2765 		N_("_Clear Servers"),
2766 		0,	0,
2767 		GTK_SIGNAL_FUNC (clear_master_servers_callback),
2768 		NULL,
2769 		&source_clear_master_servers_menu_item
2770 	},
2771 	{MENU_END,
2772 		NULL,
2773 		0,
2774 		0,
2775 		NULL,
2776 		NULL,
2777 		NULL
2778 	}
2779 };
2780 
2781 static const struct menuitem edit_menu_items[] = {
2782 	{
2783 		MENU_ITEM,
2784 		N_("_Add new Server"),
2785 		'N',
2786 		GDK_CONTROL_MASK,
2787 		GTK_SIGNAL_FUNC (add_server_callback),
2788 		NULL,
2789 		&edit_add_menu_item
2790 	},
2791 	{
2792 		MENU_ITEM,
2793 		N_("Add to _Favorites"),
2794 		0,
2795 		0,
2796 		GTK_SIGNAL_FUNC (add_to_favorites_callback),
2797 		NULL,
2798 		&edit_favadd_menu_item
2799 	},
2800 	{
2801 		MENU_ITEM,
2802 		N_("_Remove"),
2803 		'D',
2804 		GDK_CONTROL_MASK,
2805 		GTK_SIGNAL_FUNC (del_server_callback),
2806 		NULL,
2807 		&edit_delete_menu_item
2808 	},
2809 	{
2810 		MENU_ITEM,
2811 		N_("_Copy"),
2812 		'C',
2813 		GDK_CONTROL_MASK,
2814 		GTK_SIGNAL_FUNC (copy_server_callback),
2815 		NULL,
2816 		NULL
2817 	},
2818 	{
2819 		MENU_ITEM,
2820 		N_("_Copy+"),
2821 		'O',
2822 		GDK_CONTROL_MASK,
2823 		GTK_SIGNAL_FUNC (copy_server_callback_plus),
2824 		NULL,
2825 		NULL
2826 	},
2827 	{
2828 		MENU_SEPARATOR,
2829 		NULL,
2830 		0,
2831 		0,
2832 		NULL,
2833 		NULL,
2834 		NULL
2835 	},
2836 	{
2837 		MENU_ITEM,
2838 		N_("Add Default Masters"),
2839 		0,
2840 		GDK_CONTROL_MASK,
2841 		GTK_SIGNAL_FUNC (update_master_builtin_callback),
2842 		NULL,
2843 		&edit_update_master_builtin_menu_item
2844 	},
2845 	{
2846 		MENU_ITEM,
2847 		N_("Add Gslist Masters"),
2848 		0,
2849 		GDK_CONTROL_MASK,
2850 		GTK_SIGNAL_FUNC (update_master_gslist_callback),
2851 		NULL,
2852 		&edit_update_master_gslist_menu_item
2853 	},
2854 	{
2855 		MENU_ITEM,
2856 		N_("Add _Master"),
2857 		'M',
2858 		GDK_CONTROL_MASK,
2859 		GTK_SIGNAL_FUNC (add_master_callback),
2860 		NULL,
2861 		&edit_add_master_menu_item
2862 	},
2863 	{
2864 		MENU_ITEM,
2865 		N_("_Rename Master"),
2866 		0,
2867 		0,
2868 		GTK_SIGNAL_FUNC (edit_master_callback),
2869 		NULL,
2870 		&edit_edit_master_menu_item
2871 	},
2872 	{
2873 		MENU_ITEM,
2874 		N_("D_elete Master"),
2875 		0,
2876 		0,
2877 		GTK_SIGNAL_FUNC (del_master_callback),
2878 		NULL,
2879 		&edit_delete_master_menu_item
2880 	},
2881 	{
2882 		MENU_ITEM,
2883 		N_("_Clear Servers"),
2884 		0,
2885 		0,
2886 		GTK_SIGNAL_FUNC (clear_master_servers_callback),
2887 		NULL,
2888 		&edit_clear_master_servers_menu_item
2889 	},
2890 	{
2891 		MENU_SEPARATOR,
2892 		NULL,
2893 		0,
2894 		0,
2895 		NULL,
2896 		NULL,
2897 		NULL
2898 	},
2899 	{
2900 		MENU_ITEM,
2901 		N_("_Find Player"),
2902 		'F',
2903 		GDK_CONTROL_MASK,
2904 		GTK_SIGNAL_FUNC (find_player_callback),
2905 		(gpointer) FALSE,
2906 		&edit_find_player_menu_item
2907 	},
2908 	{
2909 		MENU_ITEM,
2910 		N_("Find A_gain"),
2911 		'G',
2912 		GDK_CONTROL_MASK,
2913 		GTK_SIGNAL_FUNC (find_player_callback),
2914 		(gpointer) TRUE,
2915 		&edit_find_again_menu_item
2916 	},
2917 	{
2918 		MENU_SEPARATOR,
2919 		NULL,
2920 		0,
2921 		0,
2922 		NULL,
2923 		NULL,
2924 		NULL
2925 	},
2926 	{
2927 		MENU_ITEM,
2928 		N_("Properties"),
2929 		0,
2930 		0,
2931 		GTK_SIGNAL_FUNC (properties_callback),
2932 		NULL,
2933 		&properties_menu_item
2934 	},
2935 	{
2936 		MENU_END,
2937 		NULL,
2938 		0,
2939 		0,
2940 		NULL,
2941 		NULL,
2942 		NULL
2943 	}
2944 };
2945 
2946 static const struct menuitem view_menu_items[] = {
2947 	{
2948 		MENU_ITEM,
2949 		N_("_Refresh"),
2950 		'R', GDK_CONTROL_MASK,
2951 		GTK_SIGNAL_FUNC (refresh_callback), NULL,
2952 		&view_refresh_menu_item
2953 	},
2954 	{
2955 		MENU_ITEM,
2956 		N_("Refresh _Selected"),
2957 		'S', GDK_CONTROL_MASK,
2958 		GTK_SIGNAL_FUNC (refresh_selected_callback),
2959 		NULL,
2960 		&view_refrsel_menu_item
2961 	},
2962 	{
2963 		MENU_ITEM,
2964 		N_("_Update From Master"),
2965 		'U',
2966 		GDK_CONTROL_MASK,
2967 		GTK_SIGNAL_FUNC (update_source_callback),
2968 		NULL,
2969 		&view_update_menu_item
2970 	},
2971 	{
2972 		MENU_SEPARATOR,
2973 		NULL,
2974 		0,
2975 		0,
2976 		NULL,
2977 		NULL,
2978 		NULL
2979 	},
2980 	{
2981 		MENU_CHECK_ITEM,
2982 		N_("Show _Host Names"),
2983 		'H',
2984 		GDK_CONTROL_MASK,
2985 		GTK_SIGNAL_FUNC (show_hostnames_callback),
2986 		NULL,
2987 		&view_hostnames_menu_item
2988 	},
2989 	{
2990 		MENU_CHECK_ITEM,
2991 		N_("Show Default _Port"),
2992 		0,
2993 		0,
2994 		GTK_SIGNAL_FUNC (show_default_port_callback),
2995 		NULL,
2996 		&view_defport_menu_item
2997 	},
2998 	{
2999 		MENU_END,
3000 		NULL,
3001 		0,
3002 		0,
3003 		NULL,
3004 		NULL,
3005 		NULL
3006 	}
3007 };
3008 
3009 
3010 /*
3011    baa -- Oh, this is kind of bad.  In order to allow
3012    the number of menus to be changed at compile (and in
3013    the future, run) time, I have to allocate and set
3014    up each of the filter menu items.  But that makes
3015    it no longer a const.
3016 */
3017 
3018 static const struct menuitem server_menu_items[] = {
3019 	/*
3020 	{
3021 		MENU_ITEM,
3022 		N_("_Server Filters"),
3023 		0,
3024 		0,
3025 		NULL,
3026 		0,
3027 		&server_serverfilter_menu_item
3028 	},
3029 	*/
3030 	{
3031 		MENU_ITEM,
3032 		N_("_Connect"),
3033 		0,
3034 		0,
3035 		GTK_SIGNAL_FUNC (launch_callback),
3036 		(gpointer) LAUNCH_NORMAL,
3037 		&server_connect_menu_item
3038 	},
3039 	{
3040 		MENU_ITEM,
3041 		N_("_Observe"),
3042 		0,
3043 		0,
3044 		GTK_SIGNAL_FUNC (launch_callback),
3045 		(gpointer) LAUNCH_SPECTATE,
3046 		&server_observe_menu_item
3047 	},
3048 	{
3049 		MENU_ITEM,
3050 		N_("Record _Demo"),
3051 		0,
3052 		0,
3053 		GTK_SIGNAL_FUNC (launch_callback),
3054 		(gpointer) LAUNCH_RECORD,
3055 		&server_record_menu_item
3056 	},
3057 	/*
3058 	{
3059 		MENU_ITEM,
3060 		N_("Cancel Redial"),
3061 		0,
3062 		0,
3063 		GTK_SIGNAL_FUNC (cancelredial_callback),
3064 		NULL,
3065 		&server_cancel_redial_menu_item
3066 	},
3067 	*/
3068 	{
3069 		MENU_SEPARATOR,
3070 		NULL,
3071 		0,
3072 		0,
3073 		NULL,
3074 		NULL,
3075 		NULL
3076 	},
3077 	{
3078 		MENU_ITEM,
3079 		N_("_Add new Server"),
3080 		0,
3081 		0,
3082 		GTK_SIGNAL_FUNC (add_server_callback),
3083 		NULL,
3084 		&edit_add_menu_item
3085 	},
3086 	{
3087 		MENU_ITEM,
3088 		N_("Add to _Favorites"),
3089 		0,
3090 		0,
3091 		GTK_SIGNAL_FUNC (add_to_favorites_callback),
3092 		NULL,
3093 		&server_favadd_menu_item
3094 	},
3095 	{
3096 		MENU_ITEM,
3097 		N_("_Remove"),
3098 		0,
3099 		0,
3100 		GTK_SIGNAL_FUNC (del_server_callback),
3101 		NULL,
3102 		&server_delete_menu_item
3103 	},
3104 	{
3105 		MENU_ITEM,
3106 		N_("DNS _Lookup"),
3107 		'L',
3108 		GDK_CONTROL_MASK,
3109 		GTK_SIGNAL_FUNC (resolve_callback),
3110 		NULL,
3111 		&server_resolve_menu_item
3112 	},
3113 	{
3114 		MENU_SEPARATOR,
3115 		NULL,
3116 		0,
3117 		0,
3118 		NULL,
3119 		NULL,
3120 		NULL
3121 	},
3122 	{
3123 		MENU_ITEM,
3124 		N_("_RCon"),
3125 		0,
3126 		0,
3127 		GTK_SIGNAL_FUNC (rcon_callback),
3128 		NULL,
3129 		&server_rcon_menu_item
3130 	},
3131 	{
3132 		MENU_ITEM,
3133 		N_("_Properties"),
3134 		0,
3135 		0,
3136 		GTK_SIGNAL_FUNC (properties_callback),
3137 		NULL,
3138 		&server_properties_menu_item
3139 	},
3140 	{
3141 		MENU_END,
3142 		NULL,
3143 		0,
3144 		0,
3145 		NULL,
3146 		NULL,
3147 		NULL
3148 	}
3149 };
3150 
3151 static const struct menuitem preferences_menu_items[] = {
3152 	{
3153 		MENU_ITEM,
3154 		N_("_General"),
3155 		0,
3156 		0,
3157 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3158 		(gpointer) (PREF_PAGE_GENERAL + UNKNOWN_SERVER * 256),
3159 		NULL
3160 	},
3161 	{
3162 		MENU_ITEM,
3163 		N_("_Games"),
3164 		0,
3165 		0,
3166 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3167 		(gpointer) (PREF_PAGE_GAMES + UNKNOWN_SERVER * 256),
3168 		NULL
3169 	},
3170 	{
3171 		MENU_ITEM,
3172 		N_("_Appearance"),
3173 		0,
3174 		0,
3175 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3176 		(gpointer) (PREF_PAGE_APPEARANCE + UNKNOWN_SERVER * 256),
3177 		NULL
3178 	},
3179 	{
3180 		MENU_ITEM,
3181 		N_("_QStat"),
3182 		0,
3183 		0,
3184 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3185 		(gpointer) (PREF_PAGE_QSTAT + UNKNOWN_SERVER * 256),
3186 		NULL
3187 	},
3188 	{
3189 		MENU_ITEM,
3190 		N_("_Sounds"),
3191 		0,
3192 		0,
3193 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3194 		(gpointer) (PREF_PAGE_SOUNDS + UNKNOWN_SERVER * 256),
3195 		NULL
3196 	},
3197 	{
3198 		MENU_ITEM,
3199 		N_("S_cripts"),
3200 		0,
3201 		0,
3202 		GTK_SIGNAL_FUNC (start_preferences_dialog),
3203 		(gpointer) (PREF_PAGE_SCRIPTS + UNKNOWN_SERVER * 256),
3204 		NULL
3205 	},
3206 	{
3207 		MENU_SEPARATOR,
3208 		NULL,
3209 		0,
3210 		0,
3211 		NULL,
3212 		NULL,
3213 		NULL
3214 	},
3215 	{
3216 		MENU_ITEM,
3217 		N_("_Server Filter"),
3218 		0,
3219 		0,
3220 		GTK_SIGNAL_FUNC (start_filters_cfg_dialog),
3221 		(gpointer) FILTER_SERVER,
3222 		NULL
3223 	},
3224 	{
3225 		MENU_ITEM,
3226 		N_("Player _Filter"),
3227 		0,
3228 		0,
3229 		GTK_SIGNAL_FUNC (start_filters_cfg_dialog),
3230 		(gpointer) FILTER_PLAYER,
3231 		NULL
3232 	},
3233 	{
3234 		MENU_END,
3235 		NULL,
3236 		0,
3237 		0,
3238 		NULL,
3239 		NULL,
3240 		NULL
3241 	}
3242 };
3243 
3244 static const struct menuitem help_menu_items[] = {
3245 	{
3246 		MENU_ITEM,
3247 		N_("_About"),
3248 		0,
3249 		0,
3250 		GTK_SIGNAL_FUNC (about_dialog),
3251 		NULL,
3252 		NULL
3253 	},
3254 	{
3255 		MENU_END,
3256 		NULL,
3257 		0,
3258 		0,
3259 		NULL,
3260 		NULL,
3261 		NULL
3262 	}
3263 };
3264 
3265 
3266 static const struct menuitem menubar_menu_items[] = {
3267 	{
3268 		MENU_BRANCH,
3269 		N_("_File"),
3270 		0,
3271 		0,
3272 		NULL,
3273 		&file_menu_items,
3274 		NULL
3275 	},
3276 	{
3277 		MENU_BRANCH,
3278 		N_("_Edit"),
3279 		0,
3280 		0,
3281 		NULL,
3282 		&edit_menu_items,
3283 		NULL
3284 	},
3285 	{
3286 		MENU_BRANCH,
3287 		N_("_View"),
3288 		0,
3289 		0,
3290 		NULL,
3291 		&view_menu_items,
3292 		NULL
3293 	},
3294 	{
3295 		MENU_BRANCH,
3296 		N_("_Server"),
3297 		0,
3298 		0,
3299 		NULL,
3300 		&server_menu_items,
3301 		NULL
3302 	},
3303 	{
3304 		MENU_BRANCH,
3305 		N_("_Preferences"),
3306 		0,
3307 		0,
3308 		NULL,
3309 		&preferences_menu_items,
3310 		NULL
3311 	},
3312 	{
3313 		MENU_ITEM,
3314 		N_("_Server Filters"),
3315 		0,
3316 		0,
3317 		NULL,
3318 		0,
3319 		&server_serverfilter_menu_item
3320 	},
3321 	{
3322 		MENU_BRANCH,
3323 		N_("_Help"),
3324 		0,
3325 		0,
3326 		NULL,
3327 		&help_menu_items,
3328 		NULL
3329 	},
3330 	{
3331 		MENU_END,
3332 		NULL,
3333 		0,
3334 		0,
3335 		NULL,
3336 		NULL,
3337 		NULL
3338 	}
3339 };
3340 
3341 
create_player_menu_item(char * str,int i)3342 static GtkWidget *create_player_menu_item (char *str, int i) {
3343 	GtkWidget *menu_item;
3344 	GtkWidget *hbox;
3345 	GtkWidget *label;
3346 	GtkWidget *pixmap;
3347 
3348 	menu_item = gtk_menu_item_new ();
3349 
3350 	hbox = gtk_hbox_new (FALSE, 4);
3351 	gtk_container_add (GTK_CONTAINER (menu_item), hbox);
3352 
3353 	label = gtk_label_new (str);
3354 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
3355 	gtk_widget_show (label);
3356 
3357 	pixmap = gtk_pixmap_new (group_pix[i].pix, group_pix[i].mask);
3358 	gtk_box_pack_end (GTK_BOX (hbox), pixmap, FALSE, FALSE, 0);
3359 	gtk_widget_show (pixmap);
3360 
3361 	gtk_widget_show (hbox);
3362 
3363 	return menu_item;
3364 }
3365 
3366 
create_player_menu(GtkAccelGroup * accel_group)3367 static GtkWidget *create_player_menu (GtkAccelGroup *accel_group) {
3368 	GtkWidget *menu;
3369 	GtkWidget *marker_menu;
3370 	GtkWidget *menu_item;
3371 
3372 	menu = gtk_menu_new ();
3373 
3374 	marker_menu = gtk_menu_new ();
3375 
3376 	menu_item = create_player_menu_item (_("Mark as Red"), 0);
3377 	gtk_menu_append (GTK_MENU (marker_menu), menu_item);
3378 	gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
3379 			GTK_SIGNAL_FUNC (add_to_player_filter_callback),
3380 			(gpointer) PLAYER_GROUP_RED);
3381 	gtk_widget_show (menu_item);
3382 
3383 	menu_item = create_player_menu_item (_("Mark as Green"), 1);
3384 	gtk_menu_append (GTK_MENU (marker_menu), menu_item);
3385 	gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
3386 			GTK_SIGNAL_FUNC (add_to_player_filter_callback),
3387 			(gpointer) PLAYER_GROUP_GREEN);
3388 	gtk_widget_show (menu_item);
3389 
3390 	menu_item = create_player_menu_item (_("Mark as Blue"), 2);
3391 	gtk_menu_append (GTK_MENU (marker_menu), menu_item);
3392 	gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
3393 			GTK_SIGNAL_FUNC (add_to_player_filter_callback),
3394 			(gpointer) PLAYER_GROUP_BLUE);
3395 	gtk_widget_show (menu_item);
3396 
3397 	menu_item = gtk_menu_item_new_with_label (_("Add to Player Filter"));
3398 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), marker_menu);
3399 	gtk_menu_append (GTK_MENU (menu), menu_item);
3400 	gtk_widget_show (menu_item);
3401 
3402 	player_filter_menu_item = menu_item;
3403 
3404 	return menu;
3405 }
3406 
3407 
populate_main_toolbar(void)3408 static void populate_main_toolbar (void) {
3409 	GtkWidget *pixmap;
3410 	char buf[128];
3411 	unsigned mask;
3412 	int i;
3413 
3414 	pixmap = gtk_pixmap_new (update_pix.pix, update_pix.mask);
3415 	gtk_widget_show (pixmap);
3416 
3417 	update_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3418 			_("Update"), _("Update from master"), NULL,
3419 			pixmap,
3420 			GTK_SIGNAL_FUNC (update_source_callback), NULL);
3421 
3422 	pixmap = gtk_pixmap_new (refresh_pix.pix, refresh_pix.mask);
3423 	gtk_widget_show (pixmap);
3424 
3425 	refresh_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3426 			_("Refresh"), _("Refresh current list"), NULL,
3427 			pixmap,
3428 			GTK_SIGNAL_FUNC (refresh_callback), NULL);
3429 
3430 	pixmap = gtk_pixmap_new (refrsel_pix.pix, refrsel_pix.mask);
3431 	gtk_widget_show (pixmap);
3432 
3433 	refrsel_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3434 			_("Ref.Sel."), _("Refresh selected servers"), NULL,
3435 			pixmap,
3436 			GTK_SIGNAL_FUNC (refresh_selected_callback), NULL);
3437 
3438 	pixmap = gtk_pixmap_new (stop_pix.pix, stop_pix.mask);
3439 	gtk_widget_show (pixmap);
3440 
3441 	stop_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3442 			_("Stop"), _("Stop"), NULL,
3443 			pixmap,
3444 			GTK_SIGNAL_FUNC (stop_callback), NULL);
3445 
3446 	gtk_toolbar_append_space (GTK_TOOLBAR (main_toolbar));
3447 
3448 	pixmap = gtk_pixmap_new (connect_pix.pix, connect_pix.mask);
3449 	gtk_widget_show (pixmap);
3450 
3451 	connect_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3452 			_("Connect"), _("Connect"), NULL,
3453 			pixmap,
3454 			GTK_SIGNAL_FUNC (launch_callback), (gpointer) LAUNCH_NORMAL);
3455 
3456 #if 0
3457 	pixmap = gtk_pixmap_new (observe_pix.pix, observe_pix.mask);
3458 	gtk_widget_show (pixmap);
3459 
3460 	observe_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3461 			_("Observe"), _("Observe"), NULL,
3462 			pixmap,
3463 			GTK_SIGNAL_FUNC (launch_callback), (gpointer) LAUNCH_SPECTATE);
3464 
3465 	pixmap = gtk_pixmap_new (record_pix.pix, record_pix.mask);
3466 	gtk_widget_show (pixmap);
3467 
3468 	record_button = gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3469 			_("Record"), _("Record Demo"), NULL,
3470 			pixmap,
3471 			GTK_SIGNAL_FUNC (launch_callback), (gpointer) LAUNCH_RECORD);
3472 #endif
3473 
3474 	gtk_toolbar_append_space (GTK_TOOLBAR (main_toolbar));
3475 	/*
3476 	 *  Filter buttons
3477 	 */
3478 
3479 	for (i = 0, mask = 1; i < FILTERS_TOTAL; i++, mask <<= 1) {
3480 		if (!filters[i].pix) {
3481 			filter_buttons[i] = NULL;
3482 			continue;
3483 		}
3484 		// Translators: e.g. Server Filter
3485 		g_snprintf (buf, 128, _("%s Filter Enable / Disable"), _(filters[i].name));
3486 
3487 		pixmap = gtk_pixmap_new (filters[i].pix->pix, filters[i].pix->mask);
3488 		gtk_widget_show (pixmap);
3489 
3490 		filter_buttons[i] = gtk_toolbar_append_element (
3491 				GTK_TOOLBAR (main_toolbar),
3492 				GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL,
3493 				_(filters[i].short_name), buf, NULL,
3494 				pixmap,
3495 				GTK_SIGNAL_FUNC (filter_toggle_callback), GINT_TO_POINTER(mask));
3496 
3497 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (filter_buttons[i]), ((cur_filter & mask) != 0)? TRUE : FALSE);
3498 	}
3499 
3500 #if 0
3501 	gtk_toolbar_append_space (GTK_TOOLBAR (main_toolbar));
3502 
3503 	for (i = 0, mask = 1; i < FILTERS_TOTAL; i++, mask <<= 1) {
3504 		// Translators: e.g. Server Filter Configuration
3505 		g_snprintf (buf, 128, _("%s Filter Configuration"), _(filters[i].name));
3506 
3507 		pixmap = gtk_pixmap_new (filter_cfg_pix[i].pix, filter_cfg_pix[i].mask);
3508 		gtk_widget_show (pixmap);
3509 
3510 		gtk_toolbar_append_item (GTK_TOOLBAR (main_toolbar),
3511 				_(filters[i].short_cfg_name), buf, NULL,
3512 				pixmap,
3513 				GTK_SIGNAL_FUNC (start_filters_cfg_dialog), (gpointer) i);
3514 	}
3515 
3516 	gtk_toolbar_append_space (GTK_TOOLBAR (main_toolbar));
3517 
3518 	/* filter option menu for toolbar */
3519 
3520 	filter_toolbar_label = gtk_label_new ("Filter: ");
3521 	gtk_toolbar_append_widget(GTK_TOOLBAR (main_toolbar),
3522 			filter_toolbar_label,
3523 			"Select a server filter",
3524 			"Private");
3525 	gtk_widget_show(filter_toolbar_label);
3526 
3527 	filter_option_menu_toolbar = gtk_option_menu_new ();
3528 	gtk_option_menu_set_menu (GTK_OPTION_MENU (filter_option_menu_toolbar), create_filter_menu_toolbar());
3529 
3530 	gtk_toolbar_append_widget(GTK_TOOLBAR (main_toolbar),
3531 			filter_option_menu_toolbar,
3532 			"Select a server filter",
3533 			"Private");
3534 
3535 	gtk_widget_show (filter_option_menu_toolbar);
3536 #endif
3537 
3538 	set_toolbar_appearance (GTK_TOOLBAR (main_toolbar), default_toolbar_style, default_toolbar_tips);
3539 }
3540 
3541 /** build server filter menu for menubar */
3542 #if 0
3543 static GtkWidget* create_filter_menu_toolbar() {
3544 	unsigned int i;
3545 	GtkWidget *menu;
3546 	GtkWidget *menu_item;
3547 
3548 	struct server_filter_vars* filter = NULL;
3549 
3550 	menu = gtk_menu_new();
3551 
3552 
3553 	for (i = 0;i<=server_filters->len;i++) {
3554 		char* name = NULL;
3555 		if (i == 0) {
3556 			filter = NULL;
3557 			name = _("None");
3558 		}
3559 		else {
3560 			filter = g_array_index (server_filters, struct server_filter_vars*, i-1);
3561 			name = filter->filter_name;
3562 		}
3563 
3564 		menu_item = gtk_menu_item_new_with_label(name);
3565 		gtk_menu_append (GTK_MENU (menu), menu_item);
3566 		gtk_widget_show (menu_item);
3567 
3568 		gtk_signal_connect (GTK_OBJECT (menu_item), "activate", GTK_SIGNAL_FUNC (server_filter_select_callback_toolbar), (gpointer)i); // array starts from zero but filters from 1
3569 
3570 	}
3571 
3572 	gtk_widget_show (menu);
3573 	return menu;
3574 }
3575 #endif
3576 
3577 /** build server filter menu for toolbar */
create_filter_menu()3578 static GtkWidget* create_filter_menu() {
3579 	unsigned int i;
3580 	GtkWidget *menu;
3581 	GtkWidget *menu_item;
3582 	struct server_filter_vars* filter = NULL;
3583 	GSList* rbgroup = NULL;
3584 
3585 	filter_menu_radio_buttons = NULL;
3586 
3587 	menu = gtk_menu_new();
3588 
3589 	menu_item = gtk_menu_item_new_with_label (_("Configure"));
3590 	gtk_menu_append (GTK_MENU (menu), menu_item);
3591 	gtk_widget_show (menu_item);
3592 
3593 	gtk_signal_connect (GTK_OBJECT (menu_item), "activate", GTK_SIGNAL_FUNC (start_filters_cfg_dialog), (gpointer) FILTER_SERVER);
3594 
3595 	menu_item = gtk_menu_item_new ();
3596 	gtk_widget_set_sensitive (menu_item, FALSE);
3597 	gtk_menu_append (GTK_MENU (menu), menu_item);
3598 	gtk_widget_show (menu_item);
3599 
3600 	for (i = 0;i<=server_filters->len;i++) {
3601 		char* name = NULL;
3602 		if (i == 0) {
3603 			filter = NULL;
3604 			name = _("None");
3605 		}
3606 		else {
3607 			filter = g_array_index (server_filters, struct server_filter_vars*, i-1);
3608 			name = filter->filter_name;
3609 		}
3610 
3611 		menu_item = gtk_radio_menu_item_new_with_label(rbgroup,name);
3612 		rbgroup = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item));
3613 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), FALSE);
3614 		filter_menu_radio_buttons = g_slist_append(filter_menu_radio_buttons,menu_item);
3615 
3616 		gtk_menu_append (GTK_MENU (menu), menu_item);
3617 		gtk_widget_show (menu_item);
3618 
3619 		// array starts from zero but filters from 1
3620 		gtk_signal_connect (GTK_OBJECT (menu_item), "activate",	GTK_SIGNAL_FUNC (server_filter_select_callback), GINT_TO_POINTER(i));
3621 
3622 		/*
3623 		// add separator
3624 		if (i == 0) {
3625 			menu_item = gtk_menu_item_new ();
3626 			gtk_widget_set_sensitive (menu_item, FALSE);
3627 			gtk_menu_append (GTK_MENU (menu), menu_item);
3628 			gtk_widget_show (menu_item);
3629 		}
3630 		*/
3631 	}
3632 
3633 	// filter_menu = menu;
3634 	return menu;
3635 }
3636 
quick_filter_entry_changed(GtkWidget * entry,gpointer data)3637 static void quick_filter_entry_changed(GtkWidget* entry, gpointer data) {
3638 	const char* text = gtk_entry_get_text(GTK_ENTRY(entry));
3639 	int mask = 0;
3640 
3641 	debug(3,"%d <%s>", strlen(text), text);
3642 
3643 	if (!text || !*text) {
3644 		if (filter_quick_get()) {
3645 			mask = FILTER_QUICK_MASK;
3646 		}
3647 		filter_quick_set(NULL);
3648 	}
3649 	else {
3650 		if (!filter_quick_get()) {
3651 			mask = FILTER_QUICK_MASK;
3652 		}
3653 		filter_quick_set(text);
3654 	}
3655 
3656 	filters[FILTER_QUICK].last_changed = filter_time_inc();
3657 
3658 	filter_toggle_callback(NULL, mask);
3659 }
3660 
quickfilter_delete_button_clicked(GtkWidget * widget,GtkWidget * entry)3661 void quickfilter_delete_button_clicked (GtkWidget *widget, GtkWidget* entry) {
3662 	gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
3663 	gtk_widget_grab_focus(entry);
3664 }
3665 
create_main_window(void)3666 static void create_main_window (void) {
3667 	main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3668 	gtk_signal_connect (GTK_OBJECT (main_window), "delete_event",
3669 			GTK_SIGNAL_FUNC (window_delete_event_callback), NULL);
3670 	gtk_signal_connect (GTK_OBJECT (main_window), "destroy",
3671 			GTK_SIGNAL_FUNC (ui_done), NULL);
3672 	gtk_signal_connect (GTK_OBJECT (main_window), "destroy",
3673 			GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3674 	gtk_window_set_title (GTK_WINDOW (main_window), "XQF");
3675 
3676 	register_window (main_window);
3677 
3678 	gtk_widget_realize (main_window);
3679 }
3680 
populate_main_window(void)3681 static void populate_main_window (void) {
3682 	GtkWidget *main_vbox;
3683 	GtkWidget *vbox;
3684 	GtkWidget *vbox2;
3685 	GtkWidget *hbox;
3686 	GtkWidget *hpaned;
3687 	GtkWidget *hpaned2;
3688 	GtkWidget *vpaned;
3689 	GtkWidget *menu_bar;
3690 	GtkWidget *handlebox;
3691 	GtkWidget *scrollwin;
3692 	GtkWidget *entry;
3693 	GtkWidget *label;
3694 	GtkWidget *button;
3695 	GtkWidget *pixmap;
3696 	GtkAccelGroup *accel_group;
3697 	int i;
3698 	//  char *buf;
3699 
3700 	accel_group = gtk_accel_group_new ();
3701 
3702 	/*
3703 	   Before we create the right-click server menu, we
3704 	   need to set up all of the needed filter entries.  This
3705 	   is a terrible thing to do because in menus.c, the function
3706 	   that builds the menu expects a const.  However, we are not going
3707 	   go g_free or otherwise reuse the memory we g_malloc so we should be
3708 	   okay.
3709 
3710 	   If you change the number of menu items before the various filters,
3711 	   you need to change the server_filter_widget line in xqf.h.
3712 	*/
3713 
3714 #if 0
3715 	if ((server_filter_menu_items = g_malloc(sizeof(struct menuitem) *  (MAX_SERVER_FILTERS + 4)))) {
3716 		i = 0;
3717 		j = 0;
3718 		server_filter_menu_items[i].type       = MENU_ITEM;
3719 		server_filter_menu_items[i].label      = _("Filters");
3720 		server_filter_menu_items[i].accel_key  = 0;
3721 		server_filter_menu_items[i].accel_mods = 0;
3722 		server_filter_menu_items[i].callback   = NULL;
3723 		server_filter_menu_items[i].user_data  = NULL;
3724 		server_filter_menu_items[i].widget     = &server_filter_widget[i];
3725 		i++;
3726 
3727 		server_filter_menu_items[i].type       = MENU_SEPARATOR;
3728 		server_filter_menu_items[i].label      = NULL;
3729 		server_filter_menu_items[i].accel_key  = 0;
3730 		server_filter_menu_items[i].accel_mods = 0;
3731 		server_filter_menu_items[i].callback   = NULL;
3732 		server_filter_menu_items[i].user_data  = NULL;
3733 		server_filter_menu_items[i].widget     = &server_filter_widget[i];
3734 		i++;
3735 
3736 		/* Start of the filters */
3737 		filter_start_index = i;
3738 		server_filter_menu_items[i].type       = MENU_ITEM;
3739 		server_filter_menu_items[i].label      = _("None");
3740 		server_filter_menu_items[i].accel_key  = 0;
3741 		server_filter_menu_items[i].accel_mods = 0;
3742 		server_filter_menu_items[i].callback   = GTK_SIGNAL_FUNC (server_filter_select_callback);
3743 		server_filter_menu_items[i].user_data  = (gpointer) j;
3744 		server_filter_menu_items[i].widget     = &server_filter_widget[i];
3745 
3746 		i++;
3747 		j++;
3748 
3749 		for (; i < (MAX_SERVER_FILTERS + filter_start_index); i++, j++){
3750 			buf = g_malloc(sizeof(char) * (16));
3751 			sprintf(buf, "Filter %d", j);
3752 			server_filter_menu_items[i].type       = MENU_ITEM;
3753 			server_filter_menu_items[i].label      = buf;
3754 			server_filter_menu_items[i].accel_key  = 0;
3755 			server_filter_menu_items[i].accel_mods = 0;
3756 			server_filter_menu_items[i].callback   = GTK_SIGNAL_FUNC (server_filter_select_callback);
3757 			server_filter_menu_items[i].user_data  = (gpointer) j;
3758 			server_filter_menu_items[i].widget     = &server_filter_widget[i];
3759 		}
3760 
3761 		server_filter_menu_items[i].type       = MENU_END;
3762 		server_filter_menu_items[i].label      = NULL;
3763 		server_filter_menu_items[i].accel_key  = 0;
3764 		server_filter_menu_items[i].accel_mods = 0;
3765 		server_filter_menu_items[i].callback   = NULL;
3766 		server_filter_menu_items[i].user_data  = NULL;
3767 		server_filter_menu_items[i].widget     = NULL;
3768 	}
3769 
3770 	/* Depeding on where you want the filters to appear... */
3771 #if 0
3772 	srvopt_menu_items[0].user_data = &server_filter_menu_items[0];
3773 #else
3774 	server_menu_items[0].user_data = &server_filter_menu_items[0];
3775 #endif
3776 #endif
3777 
3778 	server_menu = create_menu (srvopt_menu_items, accel_group);
3779 
3780 	server_info_menu = create_menu (srvinfo_menu_items, accel_group);
3781 
3782 	source_menu = create_menu (source_ctree_popup_menu, accel_group);
3783 
3784 	/* We will call set_server_filter_menu_list_text (); below after we
3785 	   have the filter status bar. It used to be here -baa
3786 	*/
3787 
3788 	player_menu = create_player_menu (accel_group);
3789 
3790 	main_vbox = gtk_vbox_new (FALSE, 0);
3791 	gtk_container_add (GTK_CONTAINER (main_window), main_vbox);
3792 
3793 	/*  Lazy way to get `copy to clipboard' feature working.
3794 	 *  Don't gtk_widget_show() selection_manager widget!
3795 	 */
3796 
3797 	selection_manager = GTK_EDITABLE (gtk_text_new (NULL, NULL));
3798 	gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (selection_manager), FALSE, FALSE, 0);
3799 	gtk_widget_realize (GTK_WIDGET (selection_manager));
3800 
3801 	handlebox = gtk_handle_box_new ();
3802 	gtk_box_pack_start (GTK_BOX (main_vbox), handlebox, FALSE, FALSE, 0);
3803 
3804 	menu_bar = create_menubar (menubar_menu_items, accel_group);
3805 
3806 	// add server filters to menu
3807 	server_filter_menu_items = g_array_new(FALSE,FALSE,sizeof(GtkWidget*));
3808 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (server_serverfilter_menu_item), create_filter_menu());
3809 
3810 	gtk_signal_connect_object (GTK_OBJECT (file_quit_menu_item), "activate", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (main_window));
3811 
3812 	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_hostnames_menu_item), show_hostnames);
3813 
3814 	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_defport_menu_item), show_default_port);
3815 
3816 	gtk_container_add (GTK_CONTAINER (handlebox), menu_bar);
3817 	gtk_widget_show (menu_bar);
3818 
3819 	gtk_widget_show (handlebox);
3820 
3821 	vbox = gtk_vbox_new (FALSE, 4);
3822 	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
3823 	gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
3824 
3825 	main_toolbar = gtk_toolbar_new ();
3826 	gtk_toolbar_set_orientation (GTK_TOOLBAR(main_toolbar),GTK_ORIENTATION_HORIZONTAL);
3827 	gtk_toolbar_set_style (GTK_TOOLBAR(main_toolbar),GTK_TOOLBAR_BOTH);
3828 	gtk_box_pack_start (GTK_BOX (main_vbox), main_toolbar, FALSE, FALSE, 0);
3829 
3830 	// FIXME GTK2
3831 	gtk_box_reorder_child(GTK_BOX (main_vbox), main_toolbar, 2);
3832 	populate_main_toolbar ();
3833 	gtk_widget_show (main_toolbar);
3834 
3835 	pane1_widget = hpaned = gtk_hpaned_new ();
3836 	gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
3837 
3838 	/*
3839 	 *  Sources CTree
3840 	 */
3841 
3842 	scrollwin = gtk_scrolled_window_new (NULL, NULL);
3843 	gtk_paned_add1 (GTK_PANED (hpaned), scrollwin);
3844 
3845 	source_ctree = create_source_ctree (scrollwin);
3846 
3847 	gtk_widget_show (source_ctree);
3848 
3849 	gtk_signal_connect (GTK_OBJECT (source_ctree), "tree_select_row", GTK_SIGNAL_FUNC (source_ctree_selection_changed_callback), NULL);
3850 	gtk_signal_connect (GTK_OBJECT (source_ctree), "tree_unselect_row", GTK_SIGNAL_FUNC (source_ctree_selection_changed_callback), NULL);
3851 	gtk_signal_connect (GTK_OBJECT (source_ctree), "event", GTK_SIGNAL_FUNC (source_ctree_event_callback), NULL);
3852 
3853 	gtk_widget_show (scrollwin);
3854 
3855 	pane2_widget = vpaned = gtk_vpaned_new ();
3856 	gtk_paned_add2 (GTK_PANED (hpaned), vpaned);
3857 
3858 	/*
3859 	 *  Server CList
3860 	 */
3861 
3862 	vbox2 = gtk_vbox_new (FALSE, 4);
3863 	gtk_paned_add1 (GTK_PANED (vpaned), vbox2);
3864 
3865 	hbox = gtk_hbox_new (FALSE, 4);
3866 
3867 	button = gtk_button_new();
3868 	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
3869 	pixmap = gtk_pixmap_new (delete_pix.pix, delete_pix.mask);
3870 	gtk_container_add(GTK_CONTAINER(button), pixmap);
3871 	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
3872 
3873 	gtk_widget_show_all(button);
3874 
3875 	label = gtk_label_new(_("Quick Filter:"));
3876 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
3877 	gtk_widget_show (label);
3878 
3879 	entry = gtk_entry_new();
3880 	gtk_signal_connect(GTK_OBJECT(entry), "changed", G_CALLBACK(quick_filter_entry_changed), NULL);
3881 	gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
3882 	gtk_widget_show (entry);
3883 
3884 	gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (quickfilter_delete_button_clicked), entry);
3885 
3886 	gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
3887 	gtk_widget_show (hbox);
3888 
3889 	scrollwin = gtk_scrolled_window_new (NULL, NULL);
3890 
3891 	gtk_box_pack_start (GTK_BOX (vbox2), scrollwin, TRUE, TRUE, 0);
3892 	gtk_widget_show (vbox2);
3893 
3894 	server_clist = GTK_CLIST (create_cwidget (scrollwin, &server_clist_def));
3895 
3896 	gtk_signal_connect (GTK_OBJECT (server_clist), "click_column", GTK_SIGNAL_FUNC (clist_set_sort_column), &server_clist_def);
3897 	gtk_signal_connect (GTK_OBJECT (server_clist), "event", GTK_SIGNAL_FUNC (server_clist_event_callback), NULL);
3898 	gtk_signal_connect (GTK_OBJECT (server_clist), "select_row", GTK_SIGNAL_FUNC (server_clist_select_callback), NULL);
3899 	gtk_signal_connect (GTK_OBJECT (server_clist), "unselect_row", GTK_SIGNAL_FUNC (server_clist_unselect_callback), NULL);
3900 	gtk_signal_connect (GTK_OBJECT (server_clist), "key_press_event", GTK_SIGNAL_FUNC (server_clist_keypress_callback), NULL);
3901 
3902 	gtk_clist_set_compare_func (server_clist, (GtkCListCompareFunc) server_clist_compare_func);
3903 
3904 	gtk_widget_show (GTK_WIDGET (server_clist));
3905 	gtk_widget_show (scrollwin);
3906 
3907 	pane3_widget = hpaned2 = gtk_hpaned_new ();
3908 	gtk_paned_add2 (GTK_PANED (vpaned), hpaned2);
3909 
3910 	/*
3911 	 *  Player CList
3912 	 */
3913 
3914 	scrollwin = gtk_scrolled_window_new (NULL, NULL);
3915 	gtk_paned_add1 (GTK_PANED (hpaned2), scrollwin);
3916 
3917 	player_clist = GTK_CLIST (create_cwidget (scrollwin, &player_clist_def));
3918 
3919 	gtk_signal_connect (GTK_OBJECT (player_clist), "click_column", GTK_SIGNAL_FUNC (clist_set_sort_column), &player_clist_def);
3920 	gtk_signal_connect (GTK_OBJECT (player_clist), "event", GTK_SIGNAL_FUNC (player_clist_event_callback), NULL);
3921 
3922 	gtk_clist_set_compare_func (player_clist, (GtkCListCompareFunc) player_clist_compare_func);
3923 
3924 	gtk_widget_show (GTK_WIDGET (player_clist));
3925 	gtk_widget_show (scrollwin);
3926 
3927 	/*
3928 	 *  Server Info CList
3929 	 */
3930 
3931 	scrollwin = gtk_scrolled_window_new (NULL, NULL);
3932 	gtk_paned_add2 (GTK_PANED (hpaned2), scrollwin);
3933 
3934 	srvinf_ctree = GTK_CTREE (create_cwidget (scrollwin, &srvinf_clist_def));
3935 
3936 	gtk_signal_connect (GTK_OBJECT (srvinf_ctree), "click_column", GTK_SIGNAL_FUNC (clist_set_sort_column), &srvinf_clist_def);
3937 
3938 	gtk_signal_connect (GTK_OBJECT (srvinf_ctree), "event", GTK_SIGNAL_FUNC (server_info_clist_event_callback), NULL);
3939 
3940 	gtk_clist_set_compare_func (GTK_CLIST (srvinf_ctree), (GtkCListCompareFunc) srvinf_clist_compare_func);
3941 
3942 	gtk_widget_show (GTK_WIDGET (srvinf_ctree));
3943 	gtk_widget_show (scrollwin);
3944 
3945 	gtk_widget_show (hpaned2);
3946 	gtk_widget_show (vpaned);
3947 	gtk_widget_show (hpaned);
3948 
3949 	gtk_widget_ensure_style (GTK_WIDGET (server_clist));
3950 	i = calculate_clist_row_height (GTK_WIDGET (server_clist), games[Q1_SERVER].pix->pix);
3951 	gtk_clist_set_row_height (server_clist, i);
3952 	gtk_clist_set_row_height (player_clist, i);
3953 	gtk_clist_set_row_height (GTK_CLIST (srvinf_ctree), i);
3954 	gtk_clist_set_row_height (GTK_CLIST (source_ctree), i);
3955 
3956 	/*
3957 	 *  Status Bar & Progress Bar
3958 	 */
3959 
3960 	hbox = gtk_hbox_new (FALSE, 4);
3961 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
3962 
3963 	main_status_bar = gtk_statusbar_new ();
3964 	gtk_box_pack_start (GTK_BOX (hbox), main_status_bar, TRUE, TRUE, 0);
3965 	gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(main_status_bar), FALSE);
3966 	gtk_widget_show (main_status_bar);
3967 
3968 	main_filter_status_bar = gtk_statusbar_new ();
3969 	gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(main_filter_status_bar), FALSE);
3970 	gtk_widget_set_usize (main_filter_status_bar, 100, -1);
3971 	gtk_box_pack_start (GTK_BOX (hbox), main_filter_status_bar, TRUE, TRUE, 0);
3972 	gtk_widget_show (main_filter_status_bar);
3973 
3974 	main_progress_bar = create_progress_bar ();
3975 	gtk_widget_set_usize (main_progress_bar, 200, -1);
3976 	gtk_box_pack_end (GTK_BOX (hbox), main_progress_bar, FALSE, FALSE, 0);
3977 	gtk_widget_show (main_progress_bar);
3978 
3979 	/* Make sure the current filter is dispalyed and applied if needed */
3980 	set_server_filter_menu_list_text ();
3981 
3982 	/* Refresh optionmenu on toolbar */
3983 
3984 	set_filter_option_menu_toolbar();
3985 
3986 	gtk_widget_show (hbox);
3987 
3988 	gtk_widget_show (vbox);
3989 
3990 	gtk_widget_show (main_vbox);
3991 
3992 	restore_main_window_geometry ();
3993 
3994 	window_set_icon(main_window);
3995 
3996 	gtk_window_add_accel_group (GTK_WINDOW (main_window), accel_group);
3997 	gtk_accel_group_unref (accel_group);
3998 
3999 	// Set tooltips - also in prefs_load
4000 	tooltips = gtk_tooltips_new ();
4001 	if (default_toolbar_tips) {
4002 		gtk_tooltips_enable(tooltips);
4003 	}
4004 	else {
4005 		gtk_tooltips_disable(tooltips);
4006 	}
4007 
4008 	gtk_widget_grab_focus(entry);
4009 }
4010 
play_sound(const char * sound,gboolean override)4011 void play_sound (const char *sound, gboolean override) {
4012 	play_sound_with(sound_player, sound, override);
4013 }
4014 
play_sound_with(const char * player,const char * sound,gboolean override)4015 void play_sound_with (const char* player, const char *sound, gboolean override) {
4016 	int pid;
4017 
4018 	if (!sound || !*sound) {
4019 		return;
4020 	}
4021 
4022 	if (!sound_enable && !override) {
4023 		debug(2,"sound disabled - not playing");
4024 		return;
4025 	}
4026 
4027 	if (!player || !*player) {
4028 		xqf_warning(_("no sound player configured"));
4029 		return;
4030 	}
4031 
4032 	pid = fork();
4033 	if (pid == 0) {
4034 		char *argv[3];
4035 
4036 		argv[0] = g_strdup(player);
4037 
4038 		if (sound[0] != '/') {
4039 			// Does not start with a / so prepend user_rcdir
4040 			debug(1,"Prepending user_rcdir to sound file");
4041 			argv[1] = file_in_dir(user_rcdir, sound);
4042 		}
4043 		else {
4044 			argv[1] = g_strdup(sound);
4045 		}
4046 
4047 		argv[2] = NULL;
4048 
4049 		debug(1,"sound player (program): %s",argv[0]);
4050 		debug(1,"sound to play: %s",argv[1]);
4051 		execvp(argv[0],argv);
4052 
4053 		g_free (argv[1]);
4054 
4055 		_exit (1);
4056 	}
4057 }
4058 
cmdlinehelp()4059 static void cmdlinehelp() {
4060 	puts("XQF Version " PACKAGE_VERSION);
4061 	puts(_(
4062 				"Usage:\n"
4063 				"\txqf [OPTIONS]\n"
4064 				"\n"
4065 				"OPTIONS:\n"
4066 				"\t--launch \"[SERVERTYPE] IP\"\tlaunch game on specified server\n"
4067 				"\t--add    \"[SERVERTYPE] IP\"\tadd specified server to favorites\n"
4068 				"\t--debug <level>\t\t\tset debug level\n"
4069 				"\t--version\t\t\tprint version and exit\n"));
4070 	exit(0);
4071 }
4072 
4073 static char* cmdline_add_server = NULL;
4074 static gboolean cmdline_launch = FALSE;
4075 static gboolean cmdline_newversion = FALSE;
4076 
4077 // must always return FALSE to stop g_timeout
check_cmdline_launch(gpointer nothing)4078 gboolean check_cmdline_launch(gpointer nothing) {
4079 	char* token[2] = {0};
4080 	enum server_type type = UNKNOWN_SERVER;
4081 	unsigned n = 0;
4082 	char* addrstring = NULL; // must point to a copy
4083 
4084 	if (!cmdline_add_server) {
4085 		return FALSE;
4086 	}
4087 
4088 	n = tokenize_bychar(cmdline_add_server, token, 2, ' ');
4089 
4090 	if (n == 2) // type and address given
4091 	{
4092 		type = id2type(token[0]);
4093 
4094 		if (type == UNKNOWN_SERVER) {
4095 			addrstring = add_server_dialog (&type, token[1]);
4096 		}
4097 		else {
4098 			addrstring = g_strdup(token[1]);
4099 		}
4100 	}
4101 	else if (n == 1) // only address
4102 	{
4103 		char *addr;
4104 		unsigned short port;
4105 		unsigned matches = 0;
4106 
4107 		if (!parse_address (token[0], &addr, &port)) {
4108 			dialog_ok (NULL, _("\"%s\" is not valid host[:port] combination."), token[0]);
4109 			g_free(cmdline_add_server);
4110 			return FALSE;
4111 		}
4112 
4113 		if (port) // guess the type from the port
4114 		{
4115 			unsigned i = 0;
4116 			for (i = 0; i < GAMES_TOTAL; i++) {
4117 				if (games[i].default_port == port) {
4118 					++matches;
4119 					if (type == UNKNOWN_SERVER) type = i;
4120 				}
4121 			}
4122 		}
4123 
4124 		if (!port || type == UNKNOWN_SERVER || matches > 1) {
4125 			addrstring = add_server_dialog (&type, token[0]);
4126 		}
4127 		else {
4128 			addrstring = g_strdup(cmdline_add_server);
4129 		}
4130 	}
4131 
4132 	prepare_new_server_to_favorites(type, addrstring, cmdline_launch);
4133 
4134 	g_free(cmdline_add_server);
4135 	return FALSE;
4136 }
4137 
4138 static struct option long_options[] =
4139 {
4140 	{"launch", 1, 0, 'l'},
4141 	{"add", 1, 0, 'a'},
4142 	{"debug", 1, 0, 'd'},
4143 	{"dontlaunch", 0, 0, 128},
4144 	{"version", 0, 0, 'v'},
4145 	{"help", 0, 0, 'h'},
4146 	{"newversion", 0, 0, 129},
4147 	{"nomapscan", 0, 0, 130},
4148 	{0, 0, 0, 0}
4149 };
4150 
parse_commandline(int argc,char * argv[])4151 static void parse_commandline(int argc, char* argv[]) {
4152 	while (1) {
4153 		int c;
4154 		int option_index = 0;
4155 
4156 		c = getopt_long (argc, argv, "d:l:h", long_options, &option_index);
4157 		if (c == -1) {
4158 			break;
4159 		}
4160 
4161 		switch(c) {
4162 			case 'd':
4163 				set_debug_level(atoi(optarg));
4164 				break;
4165 			case 'l':
4166 				g_free(cmdline_add_server);
4167 				cmdline_add_server = g_strdup(optarg);
4168 				cmdline_launch = TRUE;
4169 				break;
4170 			case 'a':
4171 				g_free(cmdline_add_server);
4172 				cmdline_add_server = g_strdup(optarg);
4173 				break;
4174 			case 'h':
4175 				cmdlinehelp();
4176 				break;
4177 			case 'v':
4178 				puts("XQF Version " PACKAGE_VERSION);
4179 				exit(0);
4180 				break;
4181 			case 128:
4182 				dontlaunch = TRUE;
4183 				break;
4184 			case 129:
4185 				cmdline_newversion = TRUE;
4186 				break;
4187 			case 130:
4188 				skip_startup_mapscan = TRUE;
4189 				break;
4190 			case '?':
4191 			case ':':
4192 				exit(1);
4193 				break;
4194 			default:
4195 				xqf_warning("getopt error, starting anyway ...");
4196 				return;
4197 		}
4198 	}
4199 }
4200 
add_pixmap_path_for_theme(const char * theme)4201 void add_pixmap_path_for_theme(const char* theme) {
4202 	char dir[PATH_MAX];
4203 	snprintf(dir, sizeof(dir), "%s/%s", xqf_PACKAGE_DATA_DIR, theme);
4204 	add_pixmap_directory (dir);
4205 	snprintf(dir, sizeof(dir), "%s/.local/share/xqf/%s", g_get_home_dir(), theme);
4206 	add_pixmap_directory (dir);
4207 }
4208 
init_config_path()4209 static void init_config_path() {
4210 	char dir[PATH_MAX];
4211 	config_add_dir (xqf_PACKAGE_DATA_DIR);
4212 	snprintf(dir, sizeof(dir), "%s/.local/share/xqf", g_get_home_dir());
4213 	config_add_dir (dir);
4214 	config_add_dir (user_rcdir);
4215 }
4216 
init_scripts_path()4217 static void init_scripts_path() {
4218 	char dir[PATH_MAX];
4219 	snprintf(dir, sizeof(dir), "%s/scripts", xqf_PACKAGE_DATA_DIR);
4220 	scripts_add_dir (dir);
4221 	snprintf(dir, sizeof(dir), "%s/.local/share/xqf/scripts", g_get_home_dir());
4222 	scripts_add_dir (dir);
4223 	snprintf(dir, sizeof(dir), "%s/scripts", user_rcdir);
4224 	scripts_add_dir (dir);
4225 }
4226 
main(int argc,char * argv[])4227 int main (int argc, char *argv[]) {
4228 	char *gtk_config;
4229 	char* var = NULL;
4230 	int newversion = FALSE;
4231 
4232 	xqf_start_time = time (NULL);
4233 
4234 	redialserver=0;
4235 
4236 	var = getenv("xqf_PACKAGE_DATA_DIR");
4237 	if (var) {
4238 		xqf_PACKAGE_DATA_DIR = var;
4239 	}
4240 
4241 	var = getenv("xqf_LOCALEDIR");
4242 	if (var) {
4243 		xqf_LOCALEDIR = var;
4244 	}
4245 
4246 #ifdef ENABLE_NLS
4247 	setlocale(LC_ALL, "");
4248 	bindtextdomain(PACKAGE, xqf_LOCALEDIR);
4249 	bind_textdomain_codeset(PACKAGE, "UTF-8");
4250 	textdomain(PACKAGE);
4251 #endif
4252 
4253 	set_debug_level (DEFAULT_DEBUG_LEVEL);
4254 	debug (5, "main() -- Debug Level Default Set at %d", DEFAULT_DEBUG_LEVEL);
4255 
4256 	/* migrate config directory to follow XDG  Base Directory Specification
4257 	 * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
4258 	 * https://developer.gnome.org/basedir-spec/
4259 	 * https://developer.gnome.org/glib/2.37/glib-Miscellaneous-Utility-Functions.html#g-get-user-config-dir
4260 	 */
4261 	if (!rc_migrate_dir()) {
4262 		return 1;
4263 	}
4264 
4265 	if (!init_user_info ()) {
4266 		return 1;
4267 	}
4268 
4269 	gtk_config = file_in_dir (user_rcdir, "gtkrc");
4270 	gtk_rc_add_default_file (gtk_config);
4271 	g_free (gtk_config);
4272 
4273 	gtk_init (&argc, &argv);
4274 
4275 	parse_commandline(argc,argv);
4276 
4277 	if (!GDK_PIXBUF_INSTALLED) {
4278 		xqf_warning(_("gdk-pixbuf is not installed. Some icons may not be displayed"));
4279 	}
4280 
4281 	if (dns_spawn_helper () < 0) {
4282 		xqf_error ("Unable to start DNS helper");
4283 		return 1;
4284 	}
4285 
4286 	add_pixmap_path_for_theme("default");
4287 	add_pixmap_directory(xqf_PACKAGE_DATA_DIR);
4288 
4289 	qstat_configfile = g_strconcat(xqf_PACKAGE_DATA_DIR, "/qstat.cfg", NULL);
4290 
4291 	dns_gtk_init ();
4292 
4293 	rc_check_dir ();
4294 
4295 	init_games();
4296 
4297 	init_config_path();
4298 
4299 	newversion = prefs_load () | cmdline_newversion;
4300 
4301 	if (default_icontheme) {
4302 		add_pixmap_path_for_theme(default_icontheme);
4303 	}
4304 
4305 	init_scripts_path();
4306 	scripts_load();
4307 
4308 #ifdef USE_GEOIP
4309 	geoip_init();
4310 #endif
4311 
4312 	gtk_preview_set_gamma (1.5);
4313 
4314 	props_load ();
4315 	filters_init ();
4316 
4317 	host_cache_load ();
4318 	splash_increase_progress(_("Reading server lists"),10);
4319 	init_masters (newversion);
4320 
4321 	client_init ();
4322 	ignore_sigpipe ();
4323 
4324 	on_sig(SIGUSR1, sighandler_debug);
4325 	on_sig(SIGUSR2, sighandler_debug);
4326 
4327 	add_server_init ();
4328 	add_master_init ();
4329 	psearch_init ();
4330 	rcon_init ();
4331 
4332 	if (check_qstat_version() == FALSE) {
4333 		dialog_ok(NULL, _("You need at least qstat version %s for xqf to function properly"), required_qstat_version);
4334 	}
4335 
4336 	splash_increase_progress(_("Loading icons ..."),10);
4337 
4338 	create_main_window ();
4339 
4340 	init_pixmaps (main_window);
4341 
4342 	splash_set_progress(_("Starting ..."),100);
4343 
4344 	play_sound(sound_xqf_start, 0);
4345 
4346 	script_action_start();
4347 
4348 	populate_main_window();
4349 
4350 	if (default_show_tray_icon) {
4351 		tray_init(main_window);
4352 	}
4353 	else {
4354 		gtk_widget_show (main_window);
4355 	}
4356 
4357 	source_ctree_select_source (favorites);
4358 	filter_menu_activate_current();
4359 
4360 	print_status (main_status_bar, NULL);
4361 
4362 	if (default_auto_favorites && !cmdline_add_server) refresh_callback (NULL, NULL);
4363 
4364 	destroy_splashscreen();
4365 
4366 	g_timeout_add(0, check_cmdline_launch, NULL);
4367 
4368 	debug(1,"startup time %ds", time(NULL)-xqf_start_time);
4369 
4370 	// tray_icon_set_tooltip(_("nothing yet..."));
4371 
4372 	gtk_main ();
4373 
4374 	play_sound(sound_xqf_quit, 0);
4375 	script_action_quit();
4376 
4377 	if (default_show_tray_icon) {
4378 		tray_done();
4379 	}
4380 
4381 	unregister_window (main_window);
4382 	main_window = NULL;
4383 
4384 	if (stat_process) {
4385 		stop_callback (NULL, NULL);
4386 	}
4387 
4388 	debug (1, "total servers: %d", servers_total ());
4389 	debug (1, "total uservers: %d", uservers_total ());
4390 	debug (1, "total hosts: %d", hosts_total ());
4391 #if 0
4392 	if (servers_total () > 0) {
4393 		GSList *list = all_servers (); /* Debug code, free done in two lines */
4394 
4395 		server_list_fprintf (stderr, list);
4396 		server_list_free (list);
4397 	}
4398 #endif
4399 
4400 
4401 	if (server_menu) {
4402 		debug(6, "EXIT: destroy server_menu");
4403 		gtk_widget_destroy (server_menu);
4404 		server_menu = NULL;
4405 	}
4406 
4407 	if (player_menu) {
4408 		debug(6, "EXIT: destroy player_menu");
4409 		gtk_widget_destroy (player_menu);
4410 		player_menu = NULL;
4411 	}
4412 
4413 	if (player_skin_popup) {
4414 		gtk_widget_destroy (player_skin_popup);
4415 		player_skin_popup = NULL;
4416 	}
4417 
4418 	if (server_mapshot_popup) {
4419 		gtk_widget_destroy (server_mapshot_popup);
4420 		server_mapshot_popup = NULL;
4421 	}
4422 
4423 	pixmap_cache_clear (&qw_colors_pixmap_cache, 0);
4424 	pixmap_cache_clear (&server_pixmap_cache, 0);
4425 	free_pixmaps ();
4426 
4427 	filters_done ();
4428 	props_free_all ();
4429 
4430 	debug(6, "EXIT: Free Server Lists");
4431 	g_slist_free (cur_source);
4432 	server_list_free (cur_server_list);
4433 	userver_list_free (cur_userver_list);
4434 
4435 	if (cur_server) {
4436 		server_unref (cur_server);
4437 		cur_server = NULL;
4438 	}
4439 
4440 	host_cache_save ();
4441 	host_cache_clear ();
4442 
4443 	debug(6, "EXIT: Free Master Lists");
4444 	free_masters ();
4445 
4446 	debug(6, "EXIT: Call rcon_done.");
4447 	rcon_done ();
4448 	psearch_done ();
4449 	add_server_done ();
4450 	add_master_done ();
4451 	client_detach_all ();
4452 	free_user_info ();
4453 
4454 	dns_helper_shutdown ();
4455 
4456 	config_sync ();
4457 	config_drop_all ();
4458 
4459 #ifdef USE_GEOIP
4460 	geoip_done();
4461 #endif
4462 
4463 	games_done();
4464 
4465 	debug(6, "EXIT: Done.");
4466 
4467 	return 0;
4468 }
4469