📄 gui.c
字号:
/* $Header: /home/jcb/newmj/RCS/gui.c,v 11.93 2003/09/30 23:16:44 jcb Rel $ * gui.c * A graphical interface, using gtk. *//****************** COPYRIGHT STATEMENT ********************** * This file is Copyright (c) 2000 by J. C. Bradfield. * * Distribution and use is governed by the LICENCE file that * * accompanies this file. * * The moral rights of the author are asserted. * * * ***************** DISCLAIMER OF WARRANTY ******************** * This code is not warranted fit for any purpose. See the * * LICENCE file for further information. * * * *************************************************************/#include "gui.h"#ifndef WIN32/* this is a bit sordid. This is needed for iconifying windows */#include <gdk/gdkx.h>#endifstatic const char rcs_id[] = "$Header: /home/jcb/newmj/RCS/gui.c,v 11.93 2003/09/30 23:16:44 jcb Rel $";/* local forward declarations */static AnimInfo *adjust_wall_loose(int tile_drawn);static gint check_claim_window(gpointer data);static void create_wall(void);static void clear_wall(void);static int get_relative_posn(GtkWidget *w, GtkWidget *z, int *x, int *y);static AnimInfo *playerdisp_discard(PlayerDisp *pd,Tile t);static void playerdisp_init(PlayerDisp *pd, int ori);static void playerdisp_update(PlayerDisp *pd, CMsgUnion *m);static void playerdisp_clear_discards(PlayerDisp *pd);#ifndef WIN32static void iconify_window(GtkWidget *w);static void uniconify_window(GtkWidget *w);#endifstatic int read_rcfile(char *rcfile);static void rotate_pixmap(GdkPixmap *east, GdkPixmap **south, GdkPixmap **west, GdkPixmap **north);static void change_tile_selection(GtkWidget *w,gpointer data);static void server_input_callback(gpointer data, gint source, GdkInputCondition condition);static void start_animation(AnimInfo *source,AnimInfo *target);static void stdin_input_callback(gpointer data, gint source, GdkInputCondition condition);/* currently used only in this file */void button_set_tile_without_tiletip(GtkWidget *b, Tile t, int ori);/* This global variable contains XPM data for fallback tiles. It is defined in fbtiles.c */extern char **fallbackpixmaps[];/********************* GLOBAL VARIABLES *********************//* The search path for tile sets *//* Confusing terminology: this is nothing to do with tilesets as in pungs. */#ifndef TILESETPATH#define TILESETPATH "."#endif/* And the name of the tile set */#ifndef TILESET#define TILESET NULL#endif/* separator character in search paths */#ifdef WIN32#define PATHSEP ';'#else#define PATHSEP ':'#endif/* the tileset search path given on the command line or via options. */char *tileset_path = TILESETPATH;/* ditto for the tile set */char *tileset = TILESET;static char *tilepixmapdir; /* where to find tiles */int debug = 0;int server_pversion;PlayerP our_player;int our_id;seats our_seat; /* our seat in the game *//* convert from a game seat to a position on our display board */#define game_to_board(s) ((s+NUM_SEATS-our_seat)%NUM_SEATS)/* and conversely */#define board_to_game(s) ((s+our_seat)%NUM_SEATS)/* convert from game wall position to board wall position */#define wall_game_to_board(i) ((i + wallstart) % WALL_SIZE)/* and the other way */#define wall_board_to_game(i) ((i + WALL_SIZE - wallstart)%WALL_SIZE)Game *the_game;int selected_button; /* the index of the user's selected tile, or -1 if none *//* tag for the server input callback */static gint server_callback_tag = 0;static gint stdin_callback_tag = 0; /* and stdin *//* This is a list of windows (i.e. GTK windows) that should be iconified along with the main window. It's null-terminated, for simplicity. The second element of each struct records whether the window is visible at the time the main window is iconified. (N.B. This is not actually used under Windows.) */static struct { GtkWidget **window; int visible; } windows_following_main[] = { {&textwindow,0}, {&messagewindow,0}, {&status_window,0}, /* these will only be relevant when they're standalone */ {&discard_dialog->widget,0}, {&chow_dialog,0}, {&ds_dialog,0}, {&continue_dialog,0}, {&turn_dialog,0}, {&scoring_dialog,0}, /* these should always be relevant */ {&open_dialog,0}, {&nag_window,0}, {&display_option_dialog,0}, {&game_option_dialog,0}, {&game_prefs_dialog,0}, {&playing_prefs_dialog,0}, {NULL,0} };/* callback attached to [un]map_event */static void vis_callback(GtkWidget *w UNUSED, GdkEvent *ev, gpointer data UNUSED){ if ( ev->type == GDK_MAP ) { int i;#ifndef WIN32 /* map previously open subwindows */ if ( iconify_dialogs_with_main ) { /* unfortunately, if we have a wm that raises on map, but waits for the map before raising, we will find that the main window is raised over the subwindows, which is probably not intended. So we sleep a little to try to wait for it. */ usleep(50000); for ( i = 0; windows_following_main[i].window ; i++ ) { GtkWidget *ww = *windows_following_main[i].window; if ( ww == NULL ) continue; if ( windows_following_main[i].visible ) uniconify_window(ww); } }#endif /* WIN32 */ } else if ( ev->type == GDK_UNMAP ) { int i = 0;#ifndef WIN32 /* unmap any auxiliary windows that are open, and keep state */ if ( iconify_dialogs_with_main ) { for ( i = 0; windows_following_main[i].window ; i++ ) { GtkWidget *ww = *windows_following_main[i].window; if ( ww == NULL ) continue; if ( GTK_WIDGET_VISIBLE(ww) ) { iconify_window(ww); windows_following_main[i].visible = 1; } else { windows_following_main[i].visible = 0; } } }#endif } else { warn("vis_callback called on unexpected event"); }}/* These are used as time stamps. now_time() is the time since program start measured in milliseconds. start_tv is the start time.*/static struct timeval start_tv;static int now_time(void) { struct timeval now_tv; gettimeofday(&now_tv,NULL); return (now_tv.tv_sec-start_tv.tv_sec)*1000 +(now_tv.tv_usec-start_tv.tv_usec)/1000;}int ptimeout = 15000; /* claim timeout time in milliseconds [global] */int local_timeouts = 0; /* should we handle timeouts ourselves? *//* These are the height and width of a tile (including the button border. The spacing is currently 1/4 the width of an actual tile pixmap. */static int tile_height = 0;static int tile_width = 0;static int tile_spacing = 0;/* variable concerned with the display of the wall */int showwall = -1;/* preference value for this */int pref_showwall = -1; /* do the message and game info windows get wrapped into the main ? */int info_windows_in_main = 0;/* preference values for robot names */char robot_names[3][128];/* address of server */char address[256] = "localhost:5000";/* name of player */char name[256] = "" ;/* name of the main system font (empty if use default) */char main_font_name[256] = "";/* and the "fixed" font used for text display */char text_font_name[256] = "";/* one that we believe to work */char fallback_text_font_name[256] = "";/* name of the colour of the table */char table_colour_name[256] = "";/* playing options */int playing_auto_declare_specials = 0;int playing_auto_declare_losing = 0;int playing_auto_declare_winning = 0;/* local variable to note when we are in the middle of an auto-declare */static int auto_declaring_special = 0;static int auto_declaring_hand = 0;/* to override the suppression of declaring specials dialog when we have a kong in hand */static int may_declare_kong = 0;/* a count of completed games, for nagging purposes */int completed_games = 0;int nag_state = 0; /* nag state *//* array of buttons for the tiles in the wall. button 0 is the top rightmost tile in our wall, and we count clockwise as the tiles are dealt. */static GtkWidget *wall[MAX_WALL_SIZE]; /* This gives the wall size with a sensible value when there's no game or when there's no wall established */#define WALL_SIZE ((the_game && the_game->wall.size) ? the_game->wall.size : MAX_WALL_SIZE)static int wallstart; /* where did the live wall start ? *//* given a tile number in the wall, what orientation shd it have? */#define wall_ori(n) (n < WALL_SIZE/4 ? 0 : n < 2*WALL_SIZE/4 ? 3 : n < 3*WALL_SIZE/4 ? 2 : 1)/* Pixmaps for tiles. We need one for each orientation. The reason for this slightly sick procedure is so that the error tile can also have a pixmap here, with the indexing working as expected*/static GdkPixmap *_tilepixmaps[4][MaxTile+1];/* this is global */GdkPixmap **tilepixmaps[4] = { &_tilepixmaps[0][1], &_tilepixmaps[1][1], &_tilepixmaps[2][1], &_tilepixmaps[3][1] };/* pixmaps for tong box, and mask */static GdkPixmap *tongpixmaps[4][4]; /* [ori,wind-1] */static GdkBitmap *tongmask;GtkWidget *topwindow; /* main window *//* used to remember the position of the top level window when recreating it */static gint top_x, top_y, top_pos_set;GtkWidget *menubar; /* menubar */GtkWidget *info_box; /* box to hold info windows */GtkWidget *board; /* the table area itself */GtkWidget *boardfixed; /* fixed widget enclosing boardframe */GtkWidget *boardframe; /* event box widget wrapping the board */GtkWidget *outerframe; /* outermost frame */GtkStyle *tablestyle; /* for the dark green stuff */GtkStyle *highlightstyle; /* to highlight tiles */GtkWidget *highlittile = NULL ; /* the unique highlighted tile */GtkWidget *dialoglowerbox = NULL; /* encloses dialogs when dialogs are below */GdkFont *main_font;GdkFont *fixed_font; /* a fixed width font */GdkFont *big_font; /* big font for claim windows */static GtkStyle *original_default_style;/* option table for our game preferences */GameOptionTable prefs_table;/* This gives the width of a player display in units of tiles */int pdispwidth = 0;int display_size = 0;int square_aspect = 0; /* force a square table */int animate = 0; /* do fancy animation *//* This variable determines whether animated tiles are done by moving a tile within the board, which is preferable since it means tiles don't mysteriously float above other higher windows; or by moving top-level popup windows. The only reason for the latter is that it seems to make the animation smoother under Windows. This variable is local and read-only now; it may become an option later.*/#ifdef WIN32static int animate_with_popups = 1;#elsestatic int animate_with_popups = 0;#endifint iconify_dialogs_with_main = 1;int nopopups = 0; /* suppress popups */int tiletips = 0; /* show tile tips all the time *//* the player display areas */PlayerDisp pdisps[NUM_SEATS];int calling = 0; /* disgusting global flag *//* the widget in which we put discards */GtkWidget *discard_area;/* This is an allocation structure in which we note its allocated size, at some point when we know the allocation is valid.*/GtkAllocation discard_area_alloc;/* This is used to keep a history of the discard actions in the current hand, so we can reposition the discards if we change size etc. in mid hand */struct { int count; struct { PlayerDisp *pd ; Tile t ; } hist[2*MAX_WALL_SIZE];} discard_history;GtkWidget *just_doubleclicked = NULL; /* yech yech yech. See doubleclicked *//* space round edge of dialog boxes */const gint dialog_border_width = 10;/* horiz space between buttons */const gint dialog_button_spacing = 10;/* vert space between text and buttons etc */const gint dialog_vert_spacing = 10;/* space around player boxes. N.B. this should only apply to the outermost boxes */const gint player_border_width = 10;DialogPosition dialogs_position = DialogsUnspecified;int pass_stdin = 0; /* 1 if commands are to read from stdin and passed to the server. */void usage(char *pname,char *msg) { fprintf(stderr,"%s: %s\nUsage: %s [ --id N ]\n\ [ --server ADDR ]\n\ [ --name NAME ]\n\ [ --connect ]\n\ [ --[no-]show-wall ]\n\ [ --size N ]\n\ [ --animate ]\n\ [ --tile-pixmap-dir DIR ]\n\ [ --dialogs-popup | --dialogs-below | --dialogs-central ]\n\ [ --echo-server ]\n\ [ --pass-stdin ]\n", pname,msg,pname);}#ifdef WIN32/* In Windows, we can't use sockets as they come, but have to convert them to glib channels. The following functions are passed to the sysdep.c initialize_sockets routine to do this. */static void *skt_open_transform(SOCKET s) { GIOChannel *chan; chan = g_io_channel_unix_new(s); /* don't know what do if this fails */ if ( ! chan ) { warn("Couldn't convert socket to channel"); return NULL; } return (void *)chan;}static int skt_closer(void *chan) { g_io_channel_close((GIOChannel *)chan); g_io_channel_unref((GIOChannel *)chan); /* unref the ref at creation */ return 1;}static int skt_reader(void *chan,void *buf, size_t n) { int len = 0; if ( g_io_channel_read((GIOChannel *)chan,buf,n,&len) == G_IO_ERROR_NONE ) { /* fprintf(stderr,"g_io_channel_read returned %d bytes\r\n",len); */ return len; } else { /* fprintf(stderr,"g_io_channel_read returned error\r\n"); */ return -1; }}static int skt_writer(void *chan, const void *buf, size_t n) { int len = 0; if ( g_io_channel_write((GIOChannel *)chan, (void *)buf,n,&len) == G_IO_ERROR_NONE )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -