802 lines
21 KiB
C
802 lines
21 KiB
C
/* XQF - Quake server browser and launcher
|
|
* Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h> /* va_start, va_end */
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "xqf.h"
|
|
#include "xqf-ui.h"
|
|
#include "srv-list.h"
|
|
#include "source.h"
|
|
#include "game.h"
|
|
#include "config.h"
|
|
#include "sort.h"
|
|
#include "pref.h"
|
|
#include "debug.h"
|
|
|
|
static GSList *xqf_windows = NULL;
|
|
static GtkWidget *target_window = NULL;
|
|
|
|
GtkWidget *pane1_widget;
|
|
GtkWidget *pane2_widget;
|
|
GtkWidget *pane3_widget;
|
|
|
|
GtkWidget *filter_buttons[FILTERS_TOTAL] = {0};
|
|
|
|
/* If you add a column here to appear in the server
|
|
list, you need to also add an entry in sort.h and sort.c
|
|
*/
|
|
|
|
static struct clist_column server_columns[] =
|
|
{
|
|
{
|
|
.name = N_("Name"),
|
|
.width = 180,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_SERVER_NAME, SORT_SERVER_TYPE, -1 },
|
|
.sort_name = { NULL, N_("Type") },
|
|
},
|
|
{
|
|
.name = N_("Address"),
|
|
.width = 140,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_SERVER_ADDRESS, SORT_SERVER_COUNTRY, -1 },
|
|
.sort_name = { NULL, N_("Country") },
|
|
},
|
|
{
|
|
.name = N_("Ping"),
|
|
.width = 45,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_SERVER_PING, -1 }
|
|
},
|
|
{
|
|
.name = N_("TO"),
|
|
.width = 35,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_SERVER_TO, -1 }
|
|
},
|
|
{
|
|
.name = N_("Priv"),
|
|
.width = 35,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_SERVER_PRIVATE, SORT_SERVER_ANTICHEAT, -1 },
|
|
// .Translator = "PunkBuster"
|
|
.sort_name = { NULL, N_("PB") },
|
|
},
|
|
{
|
|
.name = N_("Players"),
|
|
.width = 65,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_SERVER_PLAYERS, SORT_SERVER_MAXPLAYERS, -1 },
|
|
// .Translator = Max as in max players
|
|
.sort_name = { NULL, N_("Max") },
|
|
},
|
|
{
|
|
.name = N_("Map"),
|
|
.width = 55,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_SERVER_MAP, -1 }
|
|
},
|
|
{
|
|
.name = N_("Game"),
|
|
.width = 55,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_SERVER_GAME, -1 }
|
|
},
|
|
{
|
|
.name = N_("GameType"),
|
|
.width = 55,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_SERVER_GAMETYPE, -1 }
|
|
},
|
|
};
|
|
|
|
|
|
struct clist_def server_clist_def = {
|
|
CWIDGET_CLIST,
|
|
"Server List",
|
|
server_columns,
|
|
9,
|
|
GTK_SELECTION_EXTENDED,
|
|
630, 270,
|
|
SORT_SERVER_PING, GTK_SORT_ASCENDING
|
|
};
|
|
|
|
static struct clist_column player_columns[] =
|
|
{
|
|
{
|
|
.name = N_("Name"),
|
|
.width = 100,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_PLAYER_NAME, -1 },
|
|
},
|
|
{
|
|
.name = N_("Frags"),
|
|
.width = 50,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_PLAYER_FRAGS, -1 },
|
|
},
|
|
{
|
|
.name = N_("Colors"),
|
|
.width = 60,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_PLAYER_COLOR, -1 },
|
|
},
|
|
{
|
|
.name = N_("Skin"),
|
|
.width = 50,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_PLAYER_SKIN, -1 },
|
|
},
|
|
{
|
|
.name = N_("Ping"),
|
|
.width = 45,
|
|
.justify = GTK_JUSTIFY_RIGHT,
|
|
.sort_mode = { SORT_PLAYER_PING, -1 },
|
|
},
|
|
{
|
|
.name = N_("Time"),
|
|
.width = 45,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_PLAYER_TIME, -1 },
|
|
}
|
|
};
|
|
|
|
struct clist_def player_clist_def = {
|
|
CWIDGET_CLIST,
|
|
"Player List",
|
|
player_columns,
|
|
6,
|
|
GTK_SELECTION_SINGLE,
|
|
400, 180,
|
|
SORT_PLAYER_FRAGS, GTK_SORT_DESCENDING
|
|
};
|
|
|
|
static struct clist_column srvinf_columns[] =
|
|
{
|
|
{
|
|
.name = N_("Rule"),
|
|
.width = 90,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_INFO_RULE, -1 },
|
|
},
|
|
{
|
|
.name = N_("Value"),
|
|
.width = 80,
|
|
.justify = GTK_JUSTIFY_LEFT,
|
|
.sort_mode = { SORT_INFO_VALUE, -1 },
|
|
}
|
|
};
|
|
|
|
struct clist_def srvinf_clist_def = {
|
|
CWIDGET_CTREE,
|
|
"Rule List",
|
|
srvinf_columns,
|
|
2,
|
|
GTK_SELECTION_SINGLE,
|
|
210, 180,
|
|
SORT_INFO_RULE, GTK_SORT_ASCENDING
|
|
};
|
|
|
|
|
|
void print_status (GtkWidget *sbar, char *fmt, ...) {
|
|
unsigned context_id;
|
|
char buf[1024];
|
|
va_list ap;
|
|
|
|
if (sbar) {
|
|
buf[0] = ' '; /* indent */
|
|
buf[1] = '\0';
|
|
|
|
if (fmt) {
|
|
va_start (ap, fmt);
|
|
g_vsnprintf (buf + 1, 1024 - 1, fmt, ap);
|
|
va_end (ap);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "Status: %s\n", buf);
|
|
#endif
|
|
|
|
context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (sbar), "XQF");
|
|
|
|
gtk_statusbar_pop (GTK_STATUSBAR (sbar), context_id);
|
|
gtk_statusbar_push (GTK_STATUSBAR (sbar), context_id, buf);
|
|
}
|
|
}
|
|
|
|
|
|
int window_delete_event_callback (GtkWidget *widget, gpointer data) {
|
|
target_window = widget;
|
|
gtk_widget_destroy ((GtkWidget *) (xqf_windows->data));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void register_window (GtkWidget *window) {
|
|
xqf_windows = g_slist_prepend (xqf_windows, window);
|
|
debug (6, "%p", window);
|
|
}
|
|
|
|
|
|
void unregister_window (GtkWidget *window) {
|
|
GSList *first;
|
|
|
|
first = xqf_windows;
|
|
xqf_windows = g_slist_next (xqf_windows);
|
|
g_slist_free_1 (first);
|
|
|
|
if (target_window && target_window != window)
|
|
gtk_widget_destroy ((GtkWidget *) (xqf_windows->data));
|
|
else
|
|
target_window = NULL;
|
|
|
|
debug (6, "%p", window);
|
|
}
|
|
|
|
|
|
GtkWidget *top_window (void) {
|
|
if (xqf_windows)
|
|
return (GtkWidget *) xqf_windows->data;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef GUI_GTK2
|
|
static void clist_column_set_title (GtkCList *clist, struct clist_def *cldef, int set_mark) {
|
|
char buf[256];
|
|
|
|
if (set_mark) {
|
|
const char* name = cldef->cols[clist->sort_column].sort_name[cldef->cols[clist->sort_column].current_sort_mode];
|
|
g_snprintf (buf, 128, "%s %c", _(cldef->cols[clist->sort_column].name),
|
|
(clist->sort_type == GTK_SORT_DESCENDING)? '>' : '<');
|
|
|
|
if (name) {
|
|
snprintf (buf+strlen(buf), sizeof(buf)-strlen(buf), " (%s)", _(name));
|
|
}
|
|
gtk_label_set (GTK_LABEL (cldef->cols[clist->sort_column].widget), buf);
|
|
}
|
|
else {
|
|
gtk_label_set (GTK_LABEL (cldef->cols[clist->sort_column].widget),
|
|
_(cldef->cols[clist->sort_column].name));
|
|
}
|
|
}
|
|
|
|
|
|
GtkWidget *create_cwidget (GtkWidget *scrollwin, struct clist_def *cldef) {
|
|
GtkWidget *alignment;
|
|
GtkWidget *label;
|
|
GtkWidget *clist;
|
|
char buf[256];
|
|
int i;
|
|
|
|
switch (cldef->type) {
|
|
case CWIDGET_CLIST:
|
|
clist = gtk_clist_new (cldef->columns);
|
|
break;
|
|
|
|
case CWIDGET_CTREE:
|
|
clist = gtk_ctree_new (cldef->columns, 0);
|
|
gtk_ctree_set_line_style (GTK_CTREE (clist), GTK_CTREE_LINES_NONE);
|
|
gtk_ctree_set_expander_style (GTK_CTREE (clist), GTK_CTREE_EXPANDER_TRIANGLE);
|
|
gtk_ctree_set_indent (GTK_CTREE (clist), 10);
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
|
|
GTK_CLIST_SET_FLAG (GTK_CLIST (clist), CLIST_SHOW_TITLES);
|
|
gtk_container_add (GTK_CONTAINER (scrollwin), clist);
|
|
|
|
gtk_clist_set_selection_mode (GTK_CLIST (clist), cldef->mode);
|
|
|
|
for (i = 0; i < cldef->columns; i++) {
|
|
g_snprintf (buf, 256, "/" CONFIG_FILE "/%s Geometry/%s=%d",
|
|
cldef->name, cldef->cols[i].name, cldef->cols[i].width);
|
|
gtk_clist_set_column_width (GTK_CLIST (clist), i, config_get_int (buf));
|
|
if (cldef->cols[i].justify != GTK_JUSTIFY_LEFT) {
|
|
gtk_clist_set_column_justification (GTK_CLIST (clist), i, cldef->cols[i].justify);
|
|
}
|
|
|
|
alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
|
|
|
|
label = gtk_label_new (_(cldef->cols[i].name));
|
|
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
gtk_container_add (GTK_CONTAINER (alignment), label);
|
|
gtk_widget_show (label);
|
|
|
|
cldef->cols[i].widget = label;
|
|
|
|
gtk_clist_set_column_widget (GTK_CLIST (clist), i, alignment);
|
|
gtk_widget_show (alignment);
|
|
}
|
|
|
|
gtk_clist_set_sort_column (GTK_CLIST (clist), cldef->sort_column);
|
|
gtk_clist_set_sort_type (GTK_CLIST (clist), cldef->sort_type);
|
|
|
|
clist_column_set_title (GTK_CLIST (clist), cldef, TRUE);
|
|
|
|
return clist;
|
|
}
|
|
|
|
#define DIMOF(arr) (sizeof(arr)/sizeof(arr[0]))
|
|
|
|
void clist_set_sort_column (GtkCList *clist, int column, struct clist_def *cldef) {
|
|
if (column == clist->sort_column) {
|
|
if (clist->sort_type == GTK_SORT_DESCENDING) {
|
|
cldef->cols[column].current_sort_mode = (cldef->cols[column].current_sort_mode+1)%DIMOF(cldef->cols[column].sort_mode);
|
|
if (cldef->cols[column].sort_mode[cldef->cols[column].current_sort_mode] == -1)
|
|
cldef->cols[column].current_sort_mode = 0;
|
|
}
|
|
|
|
gtk_clist_set_sort_type (clist, GTK_SORT_DESCENDING + GTK_SORT_ASCENDING - clist->sort_type);
|
|
}
|
|
else {
|
|
cldef->cols[column].current_sort_mode = 0;
|
|
clist_column_set_title (clist, cldef, FALSE);
|
|
gtk_clist_set_sort_column (clist, column);
|
|
}
|
|
|
|
debug (3, "%d %hhd", column, cldef->cols[column].current_sort_mode);
|
|
|
|
clist_column_set_title (clist, cldef, TRUE);
|
|
gtk_clist_sort (clist);
|
|
|
|
if (clist == server_clist) {
|
|
server_clist_selection_visible ();
|
|
}
|
|
}
|
|
|
|
|
|
void source_ctree_show_node_status (GtkWidget *ctree, struct master *m) {
|
|
GtkCTreeNode *node;
|
|
struct pixmap *pix = NULL;
|
|
int is_leaf;
|
|
int expanded;
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, m);
|
|
|
|
if (m->isgroup || m == favorites) {
|
|
pix = games[m->type].pix;
|
|
}
|
|
else {
|
|
pix = &server_status[m->state];
|
|
}
|
|
|
|
gtk_ctree_get_node_info (GTK_CTREE (ctree), node, NULL, NULL, NULL, NULL, NULL, NULL, &is_leaf, &expanded);
|
|
|
|
gtk_ctree_set_node_info (GTK_CTREE (ctree), node, _(m->name), 4,
|
|
(pix)? pix->pix : NULL, (pix)? pix->mask : NULL,
|
|
(pix)? pix->pix : NULL, (pix)? pix->mask : NULL,
|
|
is_leaf, expanded);
|
|
}
|
|
|
|
|
|
static void source_ctree_enable_master_group (GtkWidget *ctree, struct master *m, int expand) {
|
|
GtkCTreeNode *node;
|
|
GtkCTreeNode *sibling = NULL;
|
|
char cfgkey[128];
|
|
GSList *list;
|
|
int expanded;
|
|
|
|
if (!m->isgroup)
|
|
return;
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, m);
|
|
|
|
if (node != NULL) {
|
|
if (expand)
|
|
gtk_ctree_expand (GTK_CTREE (ctree), node);
|
|
return;
|
|
}
|
|
|
|
g_snprintf (cfgkey, 128, "/" CONFIG_FILE "/Source Tree/%s node collapsed=false", m->name);
|
|
|
|
if (expand)
|
|
config_set_bool (cfgkey, expanded = TRUE);
|
|
else
|
|
expanded = TRUE - config_get_bool (cfgkey);
|
|
|
|
/* Find the place to insert new master group */
|
|
|
|
list = g_slist_nth (master_groups, m->type);
|
|
if (list)
|
|
list = list->next;
|
|
|
|
while (!sibling && list) {
|
|
sibling = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, (struct master *) list->data);
|
|
list = list->next;
|
|
}
|
|
|
|
node = gtk_ctree_insert_node (GTK_CTREE (ctree), NULL, sibling, NULL, 4, NULL, NULL, NULL, NULL, FALSE, expanded);
|
|
gtk_ctree_node_set_row_data (GTK_CTREE (ctree), node, m);
|
|
source_ctree_show_node_status (ctree, m);
|
|
}
|
|
|
|
|
|
/*
|
|
* Add master or update master's name if master is already in tree
|
|
* This function works only on non-group masters
|
|
*/
|
|
|
|
void source_ctree_add_master (GtkWidget *ctree, struct master *m) {
|
|
GtkCTreeNode *node;
|
|
GtkCTreeNode *parent = NULL;
|
|
struct master *group = NULL;
|
|
|
|
if (m->isgroup)
|
|
return;
|
|
|
|
// If set to display only configured games, and game is not configured,
|
|
// and it's not the 'Favorites' master, just return so the display
|
|
// isn't updated with the game type and masters.
|
|
if (!(games[m->type].cmd) && default_show_only_configured_games && m != favorites)
|
|
return;
|
|
|
|
if (m->type != UNKNOWN_SERVER) {
|
|
enum server_type type = m->master_type == MASTER_LAN? LAN_SERVER : m->type;
|
|
group = (struct master *) g_slist_nth_data (master_groups, type);
|
|
source_ctree_enable_master_group (ctree, group, TRUE);
|
|
}
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, m);
|
|
|
|
if (!node) {
|
|
if (group) {
|
|
parent = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, group);
|
|
}
|
|
node = gtk_ctree_insert_node (GTK_CTREE (ctree), parent, NULL, NULL, 4, NULL, NULL, NULL, NULL, TRUE, FALSE);
|
|
gtk_ctree_node_set_row_data (GTK_CTREE (ctree), node, m);
|
|
}
|
|
source_ctree_show_node_status (ctree, m);
|
|
}
|
|
|
|
|
|
//static void source_ctree_remove_master_group (GtkWidget *ctree,
|
|
void source_ctree_remove_master_group (GtkWidget *ctree, struct master *m) {
|
|
GtkCTreeNode *node;
|
|
|
|
if (!m->isgroup)
|
|
return;
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, m);
|
|
if (node) {
|
|
gtk_ctree_remove_node (GTK_CTREE (ctree), node);
|
|
}
|
|
}
|
|
|
|
|
|
void source_ctree_delete_master (GtkWidget *ctree, struct master *m) {
|
|
GtkCTreeNode *node;
|
|
struct master *group;
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, m);
|
|
if (!node)
|
|
return;
|
|
|
|
gtk_ctree_remove_node (GTK_CTREE (ctree), node);
|
|
|
|
/* Remove empty master group from the tree */
|
|
|
|
if (m->type != UNKNOWN_SERVER) {
|
|
group = (struct master *) g_slist_nth_data (master_groups, m->type);
|
|
if (group && (group->masters == NULL || (g_slist_length (group->masters) == 1 && group->masters->data == m))) {
|
|
source_ctree_remove_master_group (ctree, group);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void fill_source_ctree (GtkWidget *ctree) {
|
|
GSList *list;
|
|
GSList *list2;
|
|
GtkCTreeNode *node;
|
|
GtkCTreeNode *parent;
|
|
struct master *group;
|
|
struct master *m;
|
|
|
|
source_ctree_add_master (ctree, favorites);
|
|
|
|
for (list = master_groups; list; list = list->next) {
|
|
group = (struct master *) list->data;
|
|
if (group->masters) {
|
|
// If set to display only configured games, and game is not configured,
|
|
// don't update the display with the master.
|
|
if (games[group->type].cmd || !default_show_only_configured_games) {
|
|
source_ctree_enable_master_group (ctree, group, FALSE);
|
|
parent = gtk_ctree_find_by_row_data (GTK_CTREE (ctree), NULL, group);
|
|
|
|
for (list2 = group->masters; list2; list2 = list2->next) {
|
|
m = (struct master *) list2->data;
|
|
node = gtk_ctree_insert_node (GTK_CTREE (ctree), parent, NULL, NULL, 4, NULL, NULL, NULL, NULL, TRUE, FALSE);
|
|
gtk_ctree_node_set_row_data (GTK_CTREE (ctree), node, m);
|
|
source_ctree_show_node_status (ctree, m);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GtkWidget *create_source_ctree (GtkWidget *scrollwin) {
|
|
char *titles[1] = { _("Source") };
|
|
GtkWidget *ctree;
|
|
|
|
/* gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
*/
|
|
ctree = gtk_ctree_new_with_titles (1, 0, titles);
|
|
gtk_container_add (GTK_CONTAINER (scrollwin), ctree);
|
|
|
|
gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_EXTENDED);
|
|
|
|
gtk_ctree_set_line_style (GTK_CTREE (ctree), GTK_CTREE_LINES_NONE);
|
|
gtk_ctree_set_expander_style (GTK_CTREE (ctree), GTK_CTREE_EXPANDER_TRIANGLE);
|
|
gtk_ctree_set_indent (GTK_CTREE (ctree), 10);
|
|
|
|
fill_source_ctree (ctree);
|
|
|
|
return ctree;
|
|
}
|
|
|
|
|
|
void source_ctree_select_source (struct master *m) {
|
|
GtkCTreeNode *node;
|
|
GtkVisibility vis;
|
|
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (source_ctree), NULL, m);
|
|
gtk_ctree_unselect_recursive (GTK_CTREE (source_ctree), NULL);
|
|
gtk_ctree_select (GTK_CTREE (source_ctree), node);
|
|
|
|
vis = gtk_ctree_node_is_visible (GTK_CTREE (source_ctree), node);
|
|
|
|
if (vis != GTK_VISIBILITY_FULL)
|
|
gtk_ctree_node_moveto (GTK_CTREE (source_ctree), node, 0, 0.2, 0.0);
|
|
}
|
|
|
|
|
|
int calculate_clist_row_height (GtkWidget *clist, GdkPixmap *pixmap) {
|
|
int pix_h, pix_w;
|
|
int height;
|
|
|
|
gdk_window_get_size (pixmap, &pix_w, &pix_h);
|
|
|
|
height=pix_h+1;
|
|
|
|
return height;
|
|
}
|
|
#endif
|
|
|
|
void set_toolbar_appearance (GtkToolbar *toolbar, int style, int tips) {
|
|
switch (style) {
|
|
case 0: gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_ICONS); break;
|
|
case 1: gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_TEXT); break;
|
|
case 2: gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_BOTH); break;
|
|
default: break;
|
|
}
|
|
|
|
gtk_toolbar_set_tooltips (toolbar, tips);
|
|
}
|
|
|
|
/******************************* Progress Bar *****************************/
|
|
|
|
int pbar_pulse_mode;
|
|
int pbar_timeout_id;
|
|
|
|
void progress_bar_destroy_event (GtkWidget* widget) {
|
|
progress_bar_reset(widget);
|
|
}
|
|
|
|
GtkWidget *create_progress_bar (void) {
|
|
GtkWidget *pbar;
|
|
|
|
pbar = gtk_progress_bar_new ();
|
|
|
|
g_signal_connect (pbar, "destroy", G_CALLBACK (progress_bar_destroy_event), NULL);
|
|
|
|
return pbar;
|
|
}
|
|
|
|
void progress_bar_reset (GtkWidget *pbar) {
|
|
if (pbar_pulse_mode == TRUE) {
|
|
g_source_remove (pbar_timeout_id);
|
|
pbar_pulse_mode = FALSE;
|
|
}
|
|
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pbar), 0.0);
|
|
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pbar), NULL);
|
|
}
|
|
|
|
gboolean progress_bar_pulse (gpointer user_data) {
|
|
gtk_progress_bar_pulse (GTK_PROGRESS_BAR(user_data));
|
|
|
|
// Ask g_source to repeat this callback
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
void progress_bar_start (GtkWidget *pbar, int pulse_switch) {
|
|
|
|
progress_bar_reset (pbar);
|
|
|
|
if (pulse_switch && pbar_pulse_mode == FALSE) {
|
|
pbar_pulse_mode = TRUE;
|
|
gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (pbar), 0.03);
|
|
pbar_timeout_id = g_timeout_add (50, (GSourceFunc) progress_bar_pulse, (gpointer) pbar);
|
|
}
|
|
}
|
|
|
|
void save_cwidget_geometry (GtkWidget *clist, struct clist_def *cldef) {
|
|
char buf[256];
|
|
int i;
|
|
|
|
g_snprintf (buf, 256, "/" CONFIG_FILE "/%s Geometry/", cldef->name);
|
|
config_push_prefix (buf);
|
|
|
|
for (i = 0; i < cldef->columns; i++)
|
|
config_set_int (cldef->cols[i].name, GTK_CLIST (clist)->column[i].width);
|
|
|
|
config_pop_prefix ();
|
|
}
|
|
|
|
|
|
void ui_done (void) {
|
|
GtkCTreeNode *node;
|
|
char cfgkey[128];
|
|
int expanded;
|
|
GSList *list;
|
|
struct master *m;
|
|
|
|
save_cwidget_geometry (GTK_WIDGET (server_clist), &server_clist_def);
|
|
save_cwidget_geometry (GTK_WIDGET (player_clist), &player_clist_def);
|
|
save_cwidget_geometry (GTK_WIDGET (srvinf_ctree), &srvinf_clist_def);
|
|
|
|
config_push_prefix ("/" CONFIG_FILE "/Main Window Geometry/");
|
|
|
|
config_set_int ("height", main_window->allocation.height);
|
|
config_set_int ("width", main_window->allocation.width);
|
|
config_set_int ("pane1", GTK_PANED (pane1_widget)->child1->allocation.width);
|
|
config_set_int ("pane2", GTK_PANED (pane2_widget)->child1->allocation.height);
|
|
config_set_int ("pane3", GTK_PANED (pane3_widget)->child1->allocation.width);
|
|
|
|
config_pop_prefix ();
|
|
|
|
config_clean_section ("/" CONFIG_FILE "/Source Tree");
|
|
|
|
for (list = master_groups; list; list = list->next) {
|
|
m = (struct master *) list->data;
|
|
if (m->isgroup) {
|
|
node = gtk_ctree_find_by_row_data (GTK_CTREE (source_ctree), NULL, m);
|
|
if (node) {
|
|
gtk_ctree_get_node_info (GTK_CTREE (source_ctree), node,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, &expanded);
|
|
if (!expanded) {
|
|
g_snprintf (cfgkey, 128, "/" CONFIG_FILE "/Source Tree/%s node collapsed=false", m->name);
|
|
config_set_bool (cfgkey, TRUE - expanded);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void restore_main_window_geometry (void) {
|
|
int height, width;
|
|
int pane1, pane2, pane3;
|
|
|
|
config_push_prefix ("/" CONFIG_FILE "/Main Window Geometry/");
|
|
|
|
height = config_get_int ("height=480");
|
|
width = config_get_int ("width=640");
|
|
pane1 = config_get_int ("pane1");
|
|
pane2 = config_get_int ("pane2");
|
|
pane3 = config_get_int ("pane3");
|
|
|
|
config_pop_prefix ();
|
|
|
|
if (height && width) {
|
|
/* gtk_widget_set_usize (GTK_WIDGET (main_window), width, height); */
|
|
gtk_window_set_default_size (GTK_WINDOW (main_window), width, height);
|
|
}
|
|
|
|
gtk_paned_set_position (GTK_PANED (pane1_widget), (pane1)? pane1 : 120);
|
|
gtk_paned_set_position (GTK_PANED (pane2_widget), (pane2)? pane2 : server_clist_def.height +4);
|
|
gtk_paned_set_position (GTK_PANED (pane3_widget), (pane3)? pane3 : player_clist_def.height + 4);
|
|
}
|
|
|
|
GtkWidget* lookup_widget (GtkWidget* widget, const gchar* widget_name) {
|
|
GtkWidget *parent, *found_widget;
|
|
|
|
for (;;) {
|
|
if (GTK_IS_MENU (widget))
|
|
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
|
|
else
|
|
parent = widget->parent;
|
|
if (parent == NULL)
|
|
break;
|
|
widget = parent;
|
|
}
|
|
|
|
found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), widget_name);
|
|
if (!found_widget)
|
|
g_warning ("Widget not found: %s", widget_name);
|
|
return found_widget;
|
|
}
|
|
|
|
// Skip a game if it's not configured and show only configured is enabled
|
|
gboolean create_server_type_menu_filter_configured (enum server_type type) {
|
|
if (!games[type].cmd && default_show_only_configured_games)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
GtkWidget *create_server_type_menu (int active_type, gboolean (*filterfunc)(enum server_type), GtkSignalFunc callback) {
|
|
GtkWidget *option_menu = NULL;
|
|
GtkWidget *menu = NULL;
|
|
GtkWidget *menu_item = NULL;
|
|
GtkWidget *first_menu_item = NULL;
|
|
int i;
|
|
int j = 0;
|
|
int menu_type = 0;
|
|
|
|
option_menu = gtk_option_menu_new ();
|
|
|
|
menu = gtk_menu_new ();
|
|
|
|
for (i = KNOWN_SERVER_START; i < UNKNOWN_SERVER; ++i) {
|
|
if (filterfunc && !filterfunc (i))
|
|
continue;
|
|
|
|
menu_item = gtk_menu_item_new ();
|
|
|
|
if (i == active_type) {
|
|
first_menu_item = menu_item;
|
|
menu_type = j;
|
|
}
|
|
else if (!first_menu_item)
|
|
first_menu_item = menu_item;
|
|
|
|
gtk_menu_append (GTK_MENU (menu), menu_item);
|
|
|
|
gtk_container_add (GTK_CONTAINER (menu_item), game_pixmap_with_label (i));
|
|
|
|
if (callback)
|
|
g_signal_connect (GTK_OBJECT (menu_item), "activate", G_CALLBACK (callback), GINT_TO_POINTER (i));
|
|
|
|
gtk_widget_show (menu_item);
|
|
|
|
++j; // must be here in case the continue was used
|
|
}
|
|
|
|
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
|
|
|
|
// initiates callback to set servertype to first configured game
|
|
if (active_type != -1 && first_menu_item) {
|
|
gtk_menu_item_activate (GTK_MENU_ITEM (first_menu_item));
|
|
gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), menu_type);
|
|
}
|
|
|
|
return option_menu;
|
|
}
|