2011-09-30 15:32:21 +02:00
|
|
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
2003-11-01 06:35:29 +01:00
|
|
|
/*
|
2011-10-20 03:34:26 +02:00
|
|
|
* Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights
|
2006-11-09 07:05:40 +01:00
|
|
|
* reserved.
|
2003-11-01 06:35:29 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
#ifdef PLATFORM_NCURSES
|
|
|
|
|
|
|
|
#include <ncurses.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
2013-06-25 03:37:49 +02:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <time.h>
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#include <netdb.h> /* gethostbyname */
|
|
|
|
#include <errno.h>
|
|
|
|
//#include <net/netinet.h>
|
|
|
|
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include "linuxmain.h"
|
2008-06-30 05:39:27 +02:00
|
|
|
#include "linuxutl.h"
|
2013-01-08 05:40:46 +01:00
|
|
|
#include "linuxdict.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
#include "cursesmain.h"
|
|
|
|
#include "cursesask.h"
|
2003-11-16 18:17:04 +01:00
|
|
|
#include "cursesletterask.h"
|
2006-09-19 05:39:08 +02:00
|
|
|
#include "linuxbt.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
#include "model.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "board.h"
|
|
|
|
#include "engine.h"
|
|
|
|
/* #include "compipe.h" */
|
|
|
|
#include "xwproto.h"
|
|
|
|
#include "xwstream.h"
|
|
|
|
#include "xwstate.h"
|
2011-09-30 15:32:21 +02:00
|
|
|
#include "strutils.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
#include "server.h"
|
|
|
|
#include "memstream.h"
|
|
|
|
#include "util.h"
|
2006-11-07 06:46:44 +01:00
|
|
|
#include "dbgutil.h"
|
2009-01-13 14:33:56 +01:00
|
|
|
#include "linuxsms.h"
|
|
|
|
#include "linuxudp.h"
|
2013-01-24 16:49:49 +01:00
|
|
|
#include "gamesdb.h"
|
|
|
|
#include "relaycon.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
|
|
|
# define MENU_WINDOW_HEIGHT 1
|
|
|
|
# define BOARD_OFFSET 0
|
|
|
|
#else
|
|
|
|
# define MENU_WINDOW_HEIGHT 5 /* three lines plus borders */
|
|
|
|
# define BOARD_OFFSET 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CURSES_CELL_HT
|
|
|
|
# define CURSES_CELL_HT 1
|
|
|
|
#endif
|
|
|
|
#ifndef CURSES_CELL_WIDTH
|
|
|
|
# define CURSES_CELL_WIDTH 2
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#define INFINITE_TIMEOUT -1
|
2008-02-02 17:56:20 +01:00
|
|
|
#define BOARD_SCORE_PADDING 3
|
|
|
|
|
|
|
|
|
|
|
|
typedef XP_Bool (*CursesMenuHandler)(CursesAppGlobals* globals);
|
|
|
|
typedef struct MenuList {
|
|
|
|
CursesMenuHandler handler;
|
|
|
|
char* desc;
|
|
|
|
char* keyDesc;
|
|
|
|
char key;
|
|
|
|
} MenuList;
|
|
|
|
|
|
|
|
static XP_Bool handleQuit( CursesAppGlobals* globals );
|
2010-03-28 18:08:54 +02:00
|
|
|
static XP_Bool handleResend( CursesAppGlobals* globals );
|
2008-02-02 17:56:20 +01:00
|
|
|
static XP_Bool handleSpace( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleRet( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleHint( CursesAppGlobals* globals );
|
2010-07-09 15:49:32 +02:00
|
|
|
#ifdef KEYBOARD_NAV
|
2008-02-02 17:56:20 +01:00
|
|
|
static XP_Bool handleLeft( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleRight( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleUp( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleDown( CursesAppGlobals* globals );
|
2010-07-09 15:49:32 +02:00
|
|
|
#endif
|
2008-02-02 17:56:20 +01:00
|
|
|
static XP_Bool handleCommit( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleFlip( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleToggleValues( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleBackspace( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleUndo( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleReplace( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleJuggle( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleHide( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleAltLeft( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleAltRight( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleAltUp( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleAltDown( CursesAppGlobals* globals );
|
2008-02-02 21:58:44 +01:00
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
|
|
|
static XP_Bool handleRootKeyShow( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleRootKeyHide( CursesAppGlobals* globals );
|
|
|
|
#endif
|
2008-02-02 17:56:20 +01:00
|
|
|
|
|
|
|
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_sharedMenuList[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleQuit, "Quit", "Q", 'Q' },
|
2010-03-28 18:08:54 +02:00
|
|
|
{ handleResend, "Resend", "R", 'R' },
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleSpace, "Raise focus", "<spc>", ' ' },
|
|
|
|
{ handleRet, "Click/tap", "<ret>", '\r' },
|
|
|
|
{ handleHint, "Hint", "?", '?' },
|
|
|
|
|
|
|
|
#ifdef KEYBOARD_NAV
|
|
|
|
{ handleLeft, "Left", "H", 'H' },
|
|
|
|
{ handleRight, "Right", "L", 'L' },
|
|
|
|
{ handleUp, "Up", "J", 'J' },
|
|
|
|
{ handleDown, "Down", "K", 'K' },
|
|
|
|
#endif
|
|
|
|
|
|
|
|
{ handleCommit, "Commit move", "C", 'C' },
|
|
|
|
{ handleFlip, "Flip", "F", 'F' },
|
|
|
|
{ handleToggleValues, "Show values", "V", 'V' },
|
|
|
|
|
|
|
|
{ handleBackspace, "Remove from board", "<del>", 8 },
|
|
|
|
{ handleUndo, "Undo prev", "U", 'U' },
|
|
|
|
{ handleReplace, "uNdo cur", "N", 'N' },
|
|
|
|
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_boardMenuList[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleAltLeft, "Force left", "{", '{' },
|
|
|
|
{ handleAltRight, "Force right", "}", '}' },
|
|
|
|
{ handleAltUp, "Force up", "_", '_' },
|
|
|
|
{ handleAltDown, "Force down", "+", '+' },
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_scoreMenuList[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
#ifdef KEYBOARD_NAV
|
|
|
|
#endif
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_trayMenuList[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleJuggle, "Juggle", "G", 'G' },
|
|
|
|
{ handleHide, "[un]hIde", "I", 'I' },
|
|
|
|
{ handleAltLeft, "Divider left", "{", '{' },
|
|
|
|
{ handleAltRight, "Divider right", "}", '}' },
|
|
|
|
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_rootMenuListShow[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleRootKeyShow, "Press . for menu", "", '.' },
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList g_rootMenuListHide[] = {
|
2008-02-02 17:56:20 +01:00
|
|
|
{ handleRootKeyHide, "Clear menu", ".", '.' },
|
|
|
|
{ NULL, NULL, NULL, '\0'}
|
|
|
|
};
|
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
|
|
|
|
static CursesAppGlobals g_globals; /* must be global b/c of SIGWINCH_handler */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2010-07-09 15:49:32 +02:00
|
|
|
#ifdef KEYBOARD_NAV
|
2006-11-07 06:46:44 +01:00
|
|
|
static void changeMenuForFocus( CursesAppGlobals* globals,
|
|
|
|
BoardObjectType obj );
|
|
|
|
static XP_Bool handleLeft( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleRight( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleUp( CursesAppGlobals* globals );
|
|
|
|
static XP_Bool handleDown( CursesAppGlobals* globals );
|
2006-11-17 14:41:13 +01:00
|
|
|
static XP_Bool handleFocusKey( CursesAppGlobals* globals, XP_Key key );
|
2010-07-09 15:49:32 +02:00
|
|
|
#else
|
|
|
|
# define handleFocusKey( g, k ) XP_FALSE
|
|
|
|
#endif
|
2008-02-16 16:49:03 +01:00
|
|
|
static void countMenuLines( const MenuList** menuLists, int maxX, int padding,
|
2008-02-02 17:56:20 +01:00
|
|
|
int* nLinesP, int* nColsP );
|
2008-02-16 16:49:03 +01:00
|
|
|
static void drawMenuFromList( WINDOW* win, const MenuList** menuLists,
|
2008-02-02 17:56:20 +01:00
|
|
|
int nLines, int padding );
|
2008-02-16 16:49:03 +01:00
|
|
|
static CursesMenuHandler getHandlerForKey( const MenuList* list, char ch );
|
2006-11-07 06:46:44 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#ifdef MEM_DEBUG
|
2013-01-07 15:10:44 +01:00
|
|
|
# define MEMPOOL cGlobals->util->mpool,
|
2003-11-01 06:35:29 +01:00
|
|
|
#else
|
|
|
|
# define MEMPOOL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* extern int errno; */
|
|
|
|
|
|
|
|
static void
|
2008-05-24 18:08:13 +02:00
|
|
|
cursesUserError( CursesAppGlobals* globals, const char* format, ... )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start( ap, format );
|
|
|
|
|
|
|
|
vsprintf( buf, format, ap );
|
|
|
|
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* buttons[] = {"OK"};
|
|
|
|
(void)cursesask( globals, buf, VSIZE(buttons), buttons );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
} /* cursesUserError */
|
|
|
|
|
2017-02-19 04:16:32 +01:00
|
|
|
static void
|
|
|
|
curses_util_notifyPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
|
|
|
XP_U16 XP_UNUSED(col), XP_U16 XP_UNUSED(row),
|
|
|
|
const XP_UCHAR** texts, XP_U16 nTiles )
|
2011-10-29 07:15:56 +02:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
char query[128];
|
2013-07-10 03:10:41 +02:00
|
|
|
char* playerName = globals->cGlobals.gi->players[playerNum].name;
|
2011-10-29 07:15:56 +02:00
|
|
|
|
|
|
|
snprintf( query, sizeof(query),
|
|
|
|
"Pick tile for %s! (Tab or type letter to select "
|
|
|
|
"then hit <cr>.)", playerName );
|
|
|
|
|
2017-02-19 04:16:32 +01:00
|
|
|
/*index = */curses_askLetter( globals, query, texts, nTiles );
|
|
|
|
// return index;
|
2011-10-29 07:15:56 +02:00
|
|
|
} /* util_userPickTile */
|
|
|
|
|
2017-03-10 05:36:14 +01:00
|
|
|
static void
|
|
|
|
curses_util_informNeedPickTiles( XW_UtilCtxt* XP_UNUSED(uc),
|
|
|
|
XP_Bool XP_UNUSED(isInitial),
|
|
|
|
XP_U16 XP_UNUSED(player),
|
|
|
|
XP_U16 XP_UNUSED(nToPick),
|
|
|
|
XP_U16 XP_UNUSED(nFaces),
|
|
|
|
const XP_UCHAR** XP_UNUSED(faces),
|
|
|
|
const XP_U16* XP_UNUSED(counts) )
|
|
|
|
{
|
|
|
|
/* CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure; */
|
|
|
|
/* char query[128]; */
|
|
|
|
/* XP_S16 index; */
|
|
|
|
/* char* playerName = globals->cGlobals.gi->players[playerNum].name; */
|
|
|
|
|
|
|
|
/* snprintf( query, sizeof(query), */
|
|
|
|
/* "Pick tile for %s! (Tab or type letter to select " */
|
|
|
|
/* "then hit <cr>.)", playerName ); */
|
|
|
|
|
|
|
|
/* index = curses_askLetter( globals, query, texts, nTiles ); */
|
|
|
|
/* return index; */
|
2003-11-16 18:17:04 +01:00
|
|
|
} /* util_userPickTile */
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
|
|
|
curses_util_userError( XW_UtilCtxt* uc, UtilErrID id )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
2005-10-01 17:53:56 +02:00
|
|
|
XP_Bool silent;
|
2008-05-24 18:08:13 +02:00
|
|
|
const XP_UCHAR* message = linux_getErrString( id, &silent );
|
2005-10-01 17:53:56 +02:00
|
|
|
|
|
|
|
if ( silent ) {
|
|
|
|
XP_LOGF( "silent userError: %s", message );
|
|
|
|
} else {
|
|
|
|
cursesUserError( globals, message );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* curses_util_userError */
|
|
|
|
|
2017-02-17 17:10:09 +01:00
|
|
|
static void
|
|
|
|
curses_util_notifyMove( XW_UtilCtxt* uc, XWStreamCtxt* stream )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2017-02-17 17:10:09 +01:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
2003-11-01 06:35:29 +01:00
|
|
|
char* question;
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* answers[3] = {NULL};
|
2003-11-01 06:35:29 +01:00
|
|
|
short numAnswers = 0;
|
|
|
|
XP_Bool freeMe = XP_FALSE;
|
2017-02-17 17:10:09 +01:00
|
|
|
|
|
|
|
question = strFromStream( stream );
|
|
|
|
freeMe = XP_TRUE;
|
|
|
|
answers[numAnswers++] = "Cancel";
|
|
|
|
answers[numAnswers++] = "Ok";
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2017-02-17 17:10:09 +01:00
|
|
|
// result = okIndex ==
|
|
|
|
cursesask( globals, question, numAnswers, answers );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
if ( freeMe ) {
|
|
|
|
free( question );
|
|
|
|
}
|
|
|
|
} /* curses_util_userQuery */
|
|
|
|
|
2017-02-17 17:10:09 +01:00
|
|
|
static void
|
|
|
|
curses_util_notifyTrade( XW_UtilCtxt* uc, const XP_UCHAR** tiles, XP_U16 nTiles )
|
2011-10-20 03:34:26 +02:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
2017-02-17 17:10:09 +01:00
|
|
|
formatConfirmTrade( &globals->cGlobals, tiles, nTiles );
|
|
|
|
/* const char* buttons[] = { "Cancel", "Ok" }; */
|
|
|
|
/* cursesask( globals, question, VSIZE(buttons), buttons ); */
|
2011-10-20 03:34:26 +02:00
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
2006-08-16 15:44:44 +02:00
|
|
|
curses_util_trayHiddenChange( XW_UtilCtxt* XP_UNUSED(uc),
|
|
|
|
XW_TrayVisState XP_UNUSED(state),
|
|
|
|
XP_U16 XP_UNUSED(nVisibleRows) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
/* nothing to do if we don't have a scrollbar */
|
|
|
|
} /* curses_util_trayHiddenChange */
|
|
|
|
|
|
|
|
static void
|
|
|
|
cursesShowFinalScores( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
XWStreamCtxt* stream;
|
|
|
|
XP_UCHAR* text;
|
|
|
|
|
2013-01-07 15:10:44 +01:00
|
|
|
stream = mem_stream_make( MPPARM(globals->cGlobals.util->mpool)
|
2003-11-01 06:35:29 +01:00
|
|
|
globals->cGlobals.params->vtMgr,
|
|
|
|
globals, CHANNEL_NONE, NULL );
|
|
|
|
server_writeFinalScores( globals->cGlobals.game.server, stream );
|
|
|
|
|
|
|
|
text = strFromStream( stream );
|
|
|
|
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* buttons[] = { "Ok" };
|
|
|
|
(void)cursesask( globals, text, VSIZE(buttons), buttons );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
free( text );
|
2010-09-21 07:07:10 +02:00
|
|
|
stream_destroy( stream );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* cursesShowFinalScores */
|
|
|
|
|
2011-10-03 01:21:09 +02:00
|
|
|
static void
|
2016-04-15 07:16:18 +02:00
|
|
|
curses_util_informMove( XW_UtilCtxt* uc, XP_S16 XP_UNUSED(turn),
|
|
|
|
XWStreamCtxt* expl, XWStreamCtxt* XP_UNUSED(words))
|
2011-10-03 01:21:09 +02:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
char* question = strFromStream( expl );
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* buttons[] = { "Ok" };
|
|
|
|
(void)cursesask( globals, question, VSIZE(buttons), buttons );
|
2011-10-03 01:21:09 +02:00
|
|
|
free( question );
|
|
|
|
}
|
|
|
|
|
2012-05-14 16:01:02 +02:00
|
|
|
static void
|
|
|
|
curses_util_informUndo( XW_UtilCtxt* XP_UNUSED(uc))
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
2012-10-09 14:31:12 +02:00
|
|
|
curses_util_notifyGameOver( XW_UtilCtxt* uc, XP_S16 quitter )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
board_draw( globals->cGlobals.game.board );
|
|
|
|
|
|
|
|
/* game belongs in cGlobals... */
|
|
|
|
if ( globals->cGlobals.params->printHistory ) {
|
|
|
|
catGameHistory( &globals->cGlobals );
|
|
|
|
}
|
|
|
|
|
2012-10-09 14:31:12 +02:00
|
|
|
catFinalScores( &globals->cGlobals, quitter );
|
2010-03-28 18:08:54 +02:00
|
|
|
|
2008-10-26 16:33:21 +01:00
|
|
|
if ( globals->cGlobals.params->quitAfter >= 0 ) {
|
|
|
|
sleep( globals->cGlobals.params->quitAfter );
|
2009-08-30 17:23:05 +02:00
|
|
|
handleQuit( globals );
|
2003-11-01 06:35:29 +01:00
|
|
|
} else if ( globals->cGlobals.params->undoWhenDone ) {
|
2012-05-25 07:25:30 +02:00
|
|
|
server_handleUndo( globals->cGlobals.game.server, 0 );
|
2010-03-28 18:08:54 +02:00
|
|
|
} else if ( !globals->cGlobals.params->skipGameOver ) {
|
2008-10-26 16:33:21 +01:00
|
|
|
/* This is modal. Don't show if quitting */
|
2003-11-01 06:35:29 +01:00
|
|
|
cursesShowFinalScores( globals );
|
|
|
|
}
|
|
|
|
} /* curses_util_notifyGameOver */
|
|
|
|
|
2012-09-04 06:33:46 +02:00
|
|
|
static void
|
2012-10-24 16:17:21 +02:00
|
|
|
curses_util_informNetDict( XW_UtilCtxt* uc, XP_LangCode XP_UNUSED(lang),
|
|
|
|
const XP_UCHAR* XP_UNUSED_DBG(oldName),
|
2012-10-07 20:43:50 +02:00
|
|
|
const XP_UCHAR* XP_UNUSED_DBG(newName),
|
|
|
|
const XP_UCHAR* XP_UNUSED_DBG(newSum),
|
2012-09-04 06:33:46 +02:00
|
|
|
XWPhoniesChoice phoniesAction )
|
|
|
|
{
|
|
|
|
XP_USE(uc);
|
|
|
|
XP_USE(phoniesAction);
|
2012-09-09 05:23:48 +02:00
|
|
|
XP_LOGF( "%s: %s => %s (cksum: %s)", __func__, oldName, newName, newSum );
|
2012-09-04 06:33:46 +02:00
|
|
|
}
|
|
|
|
|
2013-01-08 16:28:30 +01:00
|
|
|
static void
|
|
|
|
curses_util_setIsServer( XW_UtilCtxt* uc, XP_Bool isServer )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
|
|
|
linuxSetIsServer( cGlobals, isServer );
|
|
|
|
}
|
|
|
|
|
2012-10-06 03:51:32 +02:00
|
|
|
#ifdef XWFEATURE_HILITECELL
|
2003-11-01 06:35:29 +01:00
|
|
|
static XP_Bool
|
2010-03-21 04:10:36 +01:00
|
|
|
curses_util_hiliteCell( XW_UtilCtxt* uc,
|
2006-08-16 15:44:44 +02:00
|
|
|
XP_U16 XP_UNUSED(col), XP_U16 XP_UNUSED(row) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2010-03-21 04:10:36 +01:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
if ( globals->cGlobals.params->sleepOnAnchor ) {
|
|
|
|
usleep( 10000 );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* curses_util_hiliteCell */
|
2012-10-06 03:51:32 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
static XP_Bool
|
2006-08-16 15:44:44 +02:00
|
|
|
curses_util_engineProgressCallback( XW_UtilCtxt* XP_UNUSED(uc) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* curses_util_engineProgressCallback */
|
|
|
|
|
2011-09-20 03:28:19 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
static gboolean
|
|
|
|
timerFired( gpointer data )
|
|
|
|
{
|
|
|
|
TimerInfo* ti = (TimerInfo*)data;
|
|
|
|
CommonGlobals* globals = ti->globals;
|
|
|
|
XWTimerReason why = ti - globals->timerInfo;
|
|
|
|
if ( linuxFireTimer( globals, why ) ) {
|
|
|
|
board_draw( globals->game.board );
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
2005-06-23 06:20:00 +02:00
|
|
|
curses_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why, XP_U16 when,
|
2007-05-26 16:14:01 +02:00
|
|
|
XWTimerProc proc, void* closure )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2005-09-09 05:14:11 +02:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
2011-09-20 03:28:19 +02:00
|
|
|
TimerInfo* ti = &globals->cGlobals.timerInfo[why];
|
2005-09-09 05:14:11 +02:00
|
|
|
|
2011-09-20 03:28:19 +02:00
|
|
|
ti->proc = proc;
|
|
|
|
ti->closure = closure;
|
2009-07-10 07:04:04 +02:00
|
|
|
|
2011-09-20 03:28:19 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
ti->globals = &globals->cGlobals;
|
|
|
|
(void)g_timeout_add_seconds( when, timerFired, ti );
|
|
|
|
#else
|
|
|
|
ti->when = util_getCurSeconds(uc) + when;
|
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* curses_util_setTimer */
|
|
|
|
|
2009-09-21 14:49:08 +02:00
|
|
|
static void
|
|
|
|
curses_util_clearTimer( XW_UtilCtxt* uc, XWTimerReason why )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
globals->cGlobals.timerInfo[why].proc = NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
static gboolean
|
|
|
|
onetime_idle( gpointer data )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
2011-12-22 03:45:05 +01:00
|
|
|
if ( server_do( globals->cGlobals.game.server ) ) {
|
2011-08-30 05:24:15 +02:00
|
|
|
if ( !!globals->cGlobals.game.board ) {
|
|
|
|
board_draw( globals->cGlobals.game.board );
|
|
|
|
}
|
2012-11-13 15:15:36 +01:00
|
|
|
saveGame( &globals->cGlobals );
|
2011-08-30 05:24:15 +02:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
|
|
|
curses_util_requestTime( XW_UtilCtxt* uc )
|
|
|
|
{
|
2011-08-30 05:24:15 +02:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
#ifdef USE_GLIBLOOP
|
2011-11-10 15:51:05 +01:00
|
|
|
# if 0
|
2011-08-30 05:24:15 +02:00
|
|
|
(void)g_idle_add( onetime_idle, globals );
|
2011-11-10 15:51:05 +01:00
|
|
|
# else
|
|
|
|
(void)g_timeout_add( 1,// interval,
|
|
|
|
onetime_idle, globals );
|
|
|
|
# endif
|
2011-08-30 05:24:15 +02:00
|
|
|
#else
|
2003-11-01 06:35:29 +01:00
|
|
|
/* I've created a pipe whose read-only end is plugged into the array of
|
|
|
|
fds that my event loop polls so that I can write to it to simulate
|
|
|
|
post-event on a more familiar system. It works, so no complaints! */
|
2009-01-03 19:12:34 +01:00
|
|
|
if ( 1 != write( globals->timepipe[1], "!", 1 ) ) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* curses_util_requestTime */
|
|
|
|
|
|
|
|
static void
|
2014-01-06 15:40:59 +01:00
|
|
|
initCurses( CursesAppGlobals* globals, int* widthP, int* heightP )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
WINDOW* mainWin;
|
|
|
|
WINDOW* menuWin;
|
|
|
|
WINDOW* boardWin;
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
int width, height;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
/* ncurses man page says most apps want this sequence */
|
|
|
|
mainWin = initscr();
|
|
|
|
cbreak();
|
|
|
|
noecho();
|
|
|
|
nonl();
|
|
|
|
intrflush(stdscr, FALSE);
|
2008-02-02 17:56:20 +01:00
|
|
|
keypad(stdscr, TRUE); /* effects wgetch only? */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2014-01-06 15:40:59 +01:00
|
|
|
getmaxyx( mainWin, height, width );
|
|
|
|
XP_LOGF( "%s: getmaxyx()->w:%d; h:%d", __func__, width, height );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
globals->statusLine = height - MENU_WINDOW_HEIGHT - 1;
|
|
|
|
menuWin = newwin( MENU_WINDOW_HEIGHT, width,
|
|
|
|
height-MENU_WINDOW_HEIGHT, 0 );
|
|
|
|
nodelay(menuWin, 1); /* don't block on getch */
|
|
|
|
boardWin = newwin( height-MENU_WINDOW_HEIGHT, width, 0, 0 );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
globals->menuWin = menuWin;
|
|
|
|
globals->boardWin = boardWin;
|
|
|
|
globals->mainWin = mainWin;
|
2014-01-06 15:40:59 +01:00
|
|
|
|
|
|
|
*widthP = width;
|
|
|
|
*heightP = height;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* initCurses */
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void
|
|
|
|
showStatus( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
char* str;
|
|
|
|
|
|
|
|
switch ( globals->state ) {
|
|
|
|
case XW_SERVER_WAITING_CLIENT_SIGNON:
|
|
|
|
str = "Waiting for client[s] to connnect";
|
|
|
|
break;
|
|
|
|
case XW_SERVER_READY_TO_PLAY:
|
|
|
|
str = "It's somebody's move";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
str = "unknown state";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
standout();
|
|
|
|
mvaddstr( globals->statusLine, 0, str );
|
|
|
|
/* clrtoeol(); */
|
|
|
|
standend();
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
} /* showStatus */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleQuit( CursesAppGlobals* globals )
|
|
|
|
{
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
g_main_loop_quit( globals->loop );
|
|
|
|
#else
|
2003-11-01 06:35:29 +01:00
|
|
|
globals->timeToExit = XP_TRUE;
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleQuit */
|
|
|
|
|
2010-03-28 18:08:54 +02:00
|
|
|
static XP_Bool
|
|
|
|
handleResend( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
if ( !!globals->cGlobals.game.comms ) {
|
2016-02-02 16:01:48 +01:00
|
|
|
comms_resendAll( globals->cGlobals.game.comms, COMMS_CONN_NONE,
|
|
|
|
XP_TRUE );
|
2010-03-28 18:08:54 +02:00
|
|
|
}
|
|
|
|
return XP_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-07-09 15:49:32 +02:00
|
|
|
#ifdef KEYBOARD_NAV
|
2006-11-08 06:05:11 +01:00
|
|
|
static void
|
|
|
|
checkAssignFocus( BoardCtxt* board )
|
|
|
|
{
|
|
|
|
if ( OBJ_NONE == board_getFocusOwner(board) ) {
|
|
|
|
board_focusChanged( board, OBJ_BOARD, XP_TRUE );
|
|
|
|
}
|
|
|
|
}
|
2010-07-09 15:49:32 +02:00
|
|
|
#else
|
|
|
|
# define checkAssignFocus(b)
|
|
|
|
#endif
|
2006-11-08 06:05:11 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static XP_Bool
|
2006-11-09 07:05:40 +01:00
|
|
|
handleSpace( CursesAppGlobals* globals )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
XP_Bool handled;
|
2006-11-08 06:05:11 +01:00
|
|
|
checkAssignFocus( globals->cGlobals.game.board );
|
|
|
|
|
2007-01-19 09:20:58 +01:00
|
|
|
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
|
|
|
|
XP_RAISEFOCUS_KEY, &handled );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
2006-11-09 07:05:40 +01:00
|
|
|
} /* handleSpace */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleRet( CursesAppGlobals* globals )
|
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
XP_Bool handled;
|
2007-01-19 09:20:58 +01:00
|
|
|
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
|
|
|
|
XP_RETURN_KEY, &handled );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleRet */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleHint( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
XP_Bool redo;
|
2004-06-27 06:35:42 +02:00
|
|
|
globals->doDraw = board_requestHint( globals->cGlobals.game.board,
|
|
|
|
#ifdef XWFEATURE_SEARCHLIMIT
|
|
|
|
XP_FALSE,
|
|
|
|
#endif
|
2010-07-07 14:29:04 +02:00
|
|
|
XP_FALSE, &redo );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleHint */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleCommit( CursesAppGlobals* globals )
|
|
|
|
{
|
2017-02-17 17:10:09 +01:00
|
|
|
globals->doDraw = board_commitTurn( globals->cGlobals.game.board,
|
2017-03-10 05:36:14 +01:00
|
|
|
XP_FALSE, XP_FALSE, NULL );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleCommit */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleJuggle( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
globals->doDraw = board_juggleTray( globals->cGlobals.game.board );
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleJuggle */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleHide( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
XW_TrayVisState curState =
|
|
|
|
board_getTrayVisState( globals->cGlobals.game.board );
|
|
|
|
|
|
|
|
if ( curState == TRAY_REVEALED ) {
|
|
|
|
globals->doDraw = board_hideTray( globals->cGlobals.game.board );
|
|
|
|
} else {
|
|
|
|
globals->doDraw = board_showTray( globals->cGlobals.game.board );
|
|
|
|
}
|
|
|
|
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleJuggle */
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
|
|
|
static XP_Bool
|
|
|
|
handleRootKeyShow( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
WINDOW* win;
|
|
|
|
MenuList* lists[] = { g_sharedMenuList, globals->menuList,
|
|
|
|
g_rootMenuListHide, NULL };
|
|
|
|
int winMaxY, winMaxX;
|
|
|
|
|
|
|
|
wclear( globals->menuWin );
|
|
|
|
wrefresh( globals->menuWin );
|
|
|
|
|
|
|
|
getmaxyx( globals->boardWin, winMaxY, winMaxX );
|
|
|
|
|
|
|
|
int border = 2;
|
|
|
|
int width = winMaxX - (border * 2);
|
|
|
|
int padding = 1; /* for the box */
|
|
|
|
int nLines, nCols;
|
|
|
|
countMenuLines( lists, width, padding, &nLines, &nCols );
|
|
|
|
|
|
|
|
if ( width > nCols ) {
|
|
|
|
width = nCols;
|
|
|
|
}
|
|
|
|
|
|
|
|
win = newwin( nLines+(padding*2), width+(padding*2),
|
|
|
|
((winMaxY-nLines-padding-padding)/2), (winMaxX-width)/2 );
|
|
|
|
wclear( win );
|
|
|
|
box( win, '|', '-');
|
|
|
|
|
|
|
|
drawMenuFromList( win, lists, nLines, padding );
|
|
|
|
wrefresh( win );
|
|
|
|
|
|
|
|
CursesMenuHandler handler = NULL;
|
|
|
|
while ( !handler ) {
|
|
|
|
int ch = fgetc( stdin );
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for ( i = 0; !!lists[i]; ++i ) {
|
|
|
|
handler = getHandlerForKey( lists[i], ch );
|
|
|
|
if ( !!handler ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delwin( win );
|
|
|
|
|
|
|
|
touchwin( globals->boardWin );
|
|
|
|
wrefresh( globals->boardWin );
|
|
|
|
MenuList* ml[] = { g_rootMenuListShow, NULL };
|
|
|
|
drawMenuFromList( globals->menuWin, ml, 1, 0 );
|
|
|
|
wrefresh( globals->menuWin );
|
|
|
|
|
|
|
|
return handler != NULL && (*handler)(globals);
|
|
|
|
} /* handleRootKeyShow */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleRootKeyHide( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
globals->doDraw = XP_TRUE;
|
|
|
|
return XP_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-11-17 14:41:13 +01:00
|
|
|
static XP_Bool
|
2010-07-09 15:49:32 +02:00
|
|
|
handleAltLeft( CursesAppGlobals* XP_UNUSED_KEYBOARD_NAV(globals) )
|
2006-11-17 14:41:13 +01:00
|
|
|
{
|
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_ALTLEFT );
|
|
|
|
}
|
|
|
|
|
|
|
|
static XP_Bool
|
2010-07-09 15:49:32 +02:00
|
|
|
handleAltRight( CursesAppGlobals* XP_UNUSED_KEYBOARD_NAV(globals) )
|
2006-11-17 14:41:13 +01:00
|
|
|
{
|
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_ALTRIGHT );
|
|
|
|
}
|
|
|
|
|
2006-11-22 14:49:14 +01:00
|
|
|
static XP_Bool
|
2010-07-09 15:49:32 +02:00
|
|
|
handleAltUp( CursesAppGlobals* XP_UNUSED_KEYBOARD_NAV(globals) )
|
2006-11-22 14:49:14 +01:00
|
|
|
{
|
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_ALTUP );
|
|
|
|
}
|
|
|
|
|
|
|
|
static XP_Bool
|
2010-07-09 15:49:32 +02:00
|
|
|
handleAltDown( CursesAppGlobals* XP_UNUSED_KEYBOARD_NAV(globals) )
|
2006-11-22 14:49:14 +01:00
|
|
|
{
|
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_ALTDOWN );
|
|
|
|
}
|
2006-11-17 14:41:13 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static XP_Bool
|
|
|
|
handleFlip( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
globals->doDraw = board_flip( globals->cGlobals.game.board );
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleFlip */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleToggleValues( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
globals->doDraw = board_toggle_showValues( globals->cGlobals.game.board );
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleToggleValues */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleBackspace( CursesAppGlobals* globals )
|
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
XP_Bool handled;
|
2007-01-19 09:20:58 +01:00
|
|
|
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
|
|
|
|
XP_CURSOR_KEY_DEL, &handled );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleBackspace */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleUndo( CursesAppGlobals* globals )
|
|
|
|
{
|
2012-05-25 07:25:30 +02:00
|
|
|
globals->doDraw = server_handleUndo( globals->cGlobals.game.server, 0 );
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleUndo */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleReplace( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
globals->doDraw = board_replaceTiles( globals->cGlobals.game.board );
|
|
|
|
return XP_TRUE;
|
|
|
|
} /* handleReplace */
|
|
|
|
|
2006-11-05 17:54:18 +01:00
|
|
|
#ifdef KEYBOARD_NAV
|
2006-11-14 07:47:50 +01:00
|
|
|
static XP_Bool
|
|
|
|
handleFocusKey( CursesAppGlobals* globals, XP_Key key )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
XP_Bool handled;
|
|
|
|
XP_Bool draw;
|
|
|
|
|
2006-11-08 06:05:11 +01:00
|
|
|
checkAssignFocus( globals->cGlobals.game.board );
|
2006-11-14 07:47:50 +01:00
|
|
|
|
2007-01-19 09:20:58 +01:00
|
|
|
draw = board_handleKey( globals->cGlobals.game.board, key, &handled );
|
2006-11-14 07:47:50 +01:00
|
|
|
if ( !handled ) {
|
2007-01-06 18:46:02 +01:00
|
|
|
BoardObjectType nxt;
|
|
|
|
BoardObjectType order[] = { OBJ_BOARD, OBJ_SCORE, OBJ_TRAY };
|
|
|
|
draw = linShiftFocus( &globals->cGlobals, key, order, &nxt ) || draw;
|
|
|
|
if ( nxt != OBJ_NONE ) {
|
|
|
|
changeMenuForFocus( globals, nxt );
|
|
|
|
}
|
2006-11-14 07:47:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
globals->doDraw = draw || globals->doDraw;
|
2003-11-01 06:35:29 +01:00
|
|
|
return XP_TRUE;
|
2010-07-09 15:49:32 +02:00
|
|
|
} /* handleFocusKey */
|
2006-11-14 07:47:50 +01:00
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleLeft( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_LEFT );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* handleLeft */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleRight( CursesAppGlobals* globals )
|
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_RIGHT );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* handleRight */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleUp( CursesAppGlobals* globals )
|
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_UP );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* handleUp */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
handleDown( CursesAppGlobals* globals )
|
|
|
|
{
|
2006-11-14 07:47:50 +01:00
|
|
|
return handleFocusKey( globals, XP_CURSOR_KEY_DOWN );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* handleDown */
|
2006-11-05 17:54:18 +01:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
static void
|
|
|
|
fmtMenuItem( const MenuList* item, char* buf, int maxLen )
|
|
|
|
{
|
|
|
|
snprintf( buf, maxLen, "%s %s", item->keyDesc, item->desc );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
2008-02-16 16:49:03 +01:00
|
|
|
countMenuLines( const MenuList** menuLists, int maxX, int padding,
|
2008-02-02 17:56:20 +01:00
|
|
|
int* nLinesP, int* nColsP )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2008-02-02 17:56:20 +01:00
|
|
|
int nCols = 0;
|
|
|
|
/* The menu space should be wider rather than taller, but line up by
|
|
|
|
column. So we want to use as many columns as possible to minimize the
|
|
|
|
number of lines. So start with one line and lay out. If that doesn't
|
|
|
|
fit, try two. Given the number of lines, get the max width of each
|
|
|
|
column.
|
|
|
|
*/
|
|
|
|
|
|
|
|
maxX -= padding * 2; /* on left and right side */
|
|
|
|
|
|
|
|
int nLines;
|
|
|
|
for ( nLines = 1; ; ++nLines ) {
|
|
|
|
short line = 0;
|
|
|
|
XP_Bool tooFewLines = XP_FALSE;
|
|
|
|
int maxThisCol = 0;
|
|
|
|
int i;
|
|
|
|
nCols = 0;
|
|
|
|
|
|
|
|
for ( i = 0; !tooFewLines && (NULL != menuLists[i]); ++i ) {
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList* entry;
|
2008-02-02 17:56:20 +01:00
|
|
|
for ( entry = menuLists[i]; !tooFewLines && !!entry->handler;
|
|
|
|
++entry ) {
|
|
|
|
int width;
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
/* time to switch to new column? */
|
|
|
|
if ( line == nLines ) {
|
|
|
|
nCols += maxThisCol;
|
|
|
|
if ( nCols > maxX ) {
|
|
|
|
tooFewLines = XP_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
maxThisCol = 0;
|
|
|
|
line = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmtMenuItem( entry, buf, sizeof(buf) );
|
|
|
|
width = strlen(buf) + 2; /* padding */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
if ( maxThisCol < width ) {
|
|
|
|
maxThisCol = width;
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
++line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If we get here without running out of space, we're done */
|
|
|
|
nCols += maxThisCol;
|
|
|
|
if ( !tooFewLines && (nCols < maxX) ) {
|
|
|
|
break;
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2008-02-02 17:56:20 +01:00
|
|
|
|
|
|
|
*nColsP = nCols;
|
|
|
|
*nLinesP = nLines;
|
|
|
|
} /* countMenuLines */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
static void
|
2008-02-16 16:49:03 +01:00
|
|
|
drawMenuFromList( WINDOW* win, const MenuList** menuLists,
|
2008-02-02 17:56:20 +01:00
|
|
|
int nLines, int padding )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2008-02-02 17:56:20 +01:00
|
|
|
short line = 0, col, i;
|
2003-11-01 06:35:29 +01:00
|
|
|
int winMaxY, winMaxX;
|
|
|
|
|
|
|
|
getmaxyx( win, winMaxY, winMaxX );
|
2012-09-25 16:28:02 +02:00
|
|
|
XP_USE(winMaxY);
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
int maxColWidth = 0;
|
|
|
|
if ( 0 == nLines ) {
|
|
|
|
int ignore;
|
|
|
|
countMenuLines( menuLists, winMaxX, padding, &nLines, &ignore );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2008-02-02 17:56:20 +01:00
|
|
|
col = 0;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
for ( i = 0; NULL != menuLists[i]; ++i ) {
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList* entry;
|
2008-02-02 17:56:20 +01:00
|
|
|
for ( entry = menuLists[i]; !!entry->handler; ++entry ) {
|
|
|
|
char buf[32];
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
fmtMenuItem( entry, buf, sizeof(buf) );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
mvwaddstr( win, line+padding, col+padding, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
int width = strlen(buf) + 2;
|
|
|
|
if ( width > maxColWidth ) {
|
|
|
|
maxColWidth = width;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
if ( ++line == nLines ) {
|
2003-11-01 06:35:29 +01:00
|
|
|
line = 0;
|
2008-02-02 17:56:20 +01:00
|
|
|
col += maxColWidth;
|
|
|
|
maxColWidth = 0;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* drawMenuFromList */
|
|
|
|
|
|
|
|
static void
|
|
|
|
SIGWINCH_handler( int signal )
|
|
|
|
{
|
2014-01-06 15:40:59 +01:00
|
|
|
int height, width;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
assert( signal == SIGWINCH );
|
|
|
|
|
|
|
|
endwin();
|
|
|
|
|
|
|
|
/* (*globals.drawMenu)( &globals ); */
|
|
|
|
|
2014-01-06 15:40:59 +01:00
|
|
|
getmaxyx( stdscr, height, width );
|
|
|
|
XP_LOGF( "%s:, getmaxyx()->w:%d; h:%d", __func__, width, height );
|
|
|
|
wresize( g_globals.mainWin, height-MENU_WINDOW_HEIGHT, width );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
board_draw( g_globals.cGlobals.game.board );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* SIGWINCH_handler */
|
|
|
|
|
2009-07-29 06:29:29 +02:00
|
|
|
static void
|
2009-08-30 17:23:05 +02:00
|
|
|
SIGINTTERM_handler( int XP_UNUSED(signal) )
|
2009-07-29 06:29:29 +02:00
|
|
|
{
|
2013-05-25 06:19:20 +02:00
|
|
|
if ( 1 != write( g_globals.quitpipe[1], "!", 1 ) ) {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
2009-07-29 06:29:29 +02:00
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
2014-11-05 16:41:20 +01:00
|
|
|
cursesListenOnSocket( void* closure, int newSock
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
, GIOFunc func
|
|
|
|
#endif
|
|
|
|
)
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
GIOChannel* channel = g_io_channel_unix_new( newSock );
|
2013-07-16 15:43:30 +02:00
|
|
|
XP_LOGF( "%s: created channel %p for socket %d", __func__, channel, newSock );
|
2014-10-15 16:26:18 +02:00
|
|
|
XP_ASSERT( !!func );
|
2014-11-05 16:41:20 +01:00
|
|
|
(void)g_io_add_watch( channel,
|
|
|
|
G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
|
|
|
|
func, closure );
|
2011-08-30 05:24:15 +02:00
|
|
|
#else
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_ASSERT( globals->fdCount+1 < FD_MAX );
|
|
|
|
|
2009-01-13 14:33:56 +01:00
|
|
|
XP_WARNF( "%s: setting fd[%d] to %d", __func__, globals->fdCount, newSock );
|
2003-11-01 06:35:29 +01:00
|
|
|
globals->fdArray[globals->fdCount].fd = newSock;
|
2009-07-29 06:29:29 +02:00
|
|
|
globals->fdArray[globals->fdCount].events = POLLIN | POLLERR | POLLHUP;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
++globals->fdCount;
|
2009-01-13 14:33:56 +01:00
|
|
|
XP_LOGF( "%s: there are now %d sources to poll",
|
|
|
|
__func__, globals->fdCount );
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* cursesListenOnSocket */
|
|
|
|
|
2005-03-19 23:07:53 +01:00
|
|
|
static void
|
2014-11-05 16:41:20 +01:00
|
|
|
curses_socket_added( void* closure, int newSock, GIOFunc func )
|
2005-03-19 23:07:53 +01:00
|
|
|
{
|
2014-11-05 16:41:20 +01:00
|
|
|
// CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
2005-03-19 23:07:53 +01:00
|
|
|
if ( newSock != -1 ) {
|
2014-11-05 16:41:20 +01:00
|
|
|
cursesListenOnSocket( closure, newSock
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
2014-10-15 16:26:18 +02:00
|
|
|
, func
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
|
|
|
);
|
2005-03-19 23:07:53 +01:00
|
|
|
}
|
2009-07-31 15:03:05 +02:00
|
|
|
|
|
|
|
#ifdef XWFEATURE_RELAY
|
2014-11-05 16:41:20 +01:00
|
|
|
/* XP_ASSERT( !globals->cGlobals.relaySocket ); */
|
|
|
|
/* globals->cGlobals.relaySocket = newSock; */
|
2009-07-31 15:03:05 +02:00
|
|
|
#endif
|
2005-03-19 23:07:53 +01:00
|
|
|
} /* curses_socket_changed */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2013-01-24 16:49:49 +01:00
|
|
|
static void
|
|
|
|
curses_onGameSaved( void* closure, sqlite3_int64 rowid,
|
|
|
|
XP_Bool XP_UNUSED(firstTime) )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
|
|
|
/* May not be recorded */
|
|
|
|
globals->cGlobals.selRow = rowid;
|
|
|
|
}
|
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
2013-05-25 06:19:20 +02:00
|
|
|
static gboolean
|
|
|
|
handle_quitwrite( GIOChannel* XP_UNUSED(source), GIOCondition XP_UNUSED(condition), gpointer data )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
|
|
|
handleQuit( globals );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
static gboolean
|
|
|
|
fire_acceptor( GIOChannel* source, GIOCondition condition, gpointer data )
|
|
|
|
{
|
|
|
|
if ( 0 != (G_IO_IN & condition) ) {
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
|
|
|
|
|
|
|
int fd = g_io_channel_unix_get_fd( source );
|
|
|
|
XP_ASSERT( fd == globals->csInfo.server.serverSocket );
|
|
|
|
(*globals->cGlobals.acceptor)( fd, globals );
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-09-19 05:39:08 +02:00
|
|
|
static void
|
2007-11-28 04:59:26 +01:00
|
|
|
curses_socket_acceptor( int listener, Acceptor func, CommonGlobals* cGlobals,
|
2007-12-05 07:28:51 +01:00
|
|
|
void** XP_UNUSED(storage) )
|
2006-09-19 05:39:08 +02:00
|
|
|
{
|
2012-02-09 14:16:32 +01:00
|
|
|
if ( -1 == listener ) {
|
|
|
|
XP_LOGF( "%s: removal of listener not implemented!!!!!", __func__ );
|
|
|
|
} else {
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)cGlobals;
|
|
|
|
XP_ASSERT( !cGlobals->acceptor || (func == cGlobals->acceptor) );
|
|
|
|
cGlobals->acceptor = func;
|
|
|
|
globals->csInfo.server.serverSocket = listener;
|
|
|
|
cursesListenOnSocket( globals, listener
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
2012-02-09 14:16:32 +01:00
|
|
|
, fire_acceptor
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2012-02-09 14:16:32 +01:00
|
|
|
);
|
|
|
|
}
|
2006-09-19 05:39:08 +02:00
|
|
|
}
|
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifndef USE_GLIBLOOP
|
2009-02-01 16:50:58 +01:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-09-09 05:14:11 +02:00
|
|
|
static int
|
2007-12-05 07:28:51 +01:00
|
|
|
figureTimeout( CursesAppGlobals* globals )
|
2005-09-09 05:14:11 +02:00
|
|
|
{
|
|
|
|
int result = INFINITE_TIMEOUT;
|
2009-07-10 07:04:04 +02:00
|
|
|
XWTimerReason ii;
|
|
|
|
XP_U32 now = util_getCurSeconds( globals->cGlobals.params->util );
|
|
|
|
|
|
|
|
now *= 1000;
|
|
|
|
|
|
|
|
for ( ii = 0; ii < NUM_TIMERS_PLUS_ONE; ++ii ) {
|
|
|
|
TimerInfo* tip = &globals->cGlobals.timerInfo[ii];
|
|
|
|
if ( !!tip->proc ) {
|
|
|
|
XP_U32 then = tip->when * 1000;
|
|
|
|
if ( now >= then ) {
|
|
|
|
result = 0;
|
|
|
|
break; /* if one's immediate, we're done */
|
|
|
|
} else {
|
|
|
|
then -= now;
|
|
|
|
if ( result == -1 || then < result ) {
|
|
|
|
result = then;
|
|
|
|
}
|
|
|
|
}
|
2005-09-09 05:14:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* figureTimeout */
|
2008-01-02 02:43:45 +01:00
|
|
|
#else
|
|
|
|
# define figureTimeout(g) INFINITE_TIMEOUT
|
|
|
|
#endif
|
2005-09-09 05:14:11 +02:00
|
|
|
|
2009-08-21 14:15:40 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2009-07-10 07:04:04 +02:00
|
|
|
static void
|
|
|
|
fireCursesTimer( CursesAppGlobals* globals )
|
|
|
|
{
|
|
|
|
XWTimerReason ii;
|
|
|
|
TimerInfo* smallestTip = NULL;
|
|
|
|
|
|
|
|
for ( ii = 0; ii < NUM_TIMERS_PLUS_ONE; ++ii ) {
|
|
|
|
TimerInfo* tip = &globals->cGlobals.timerInfo[ii];
|
|
|
|
if ( !!tip->proc ) {
|
|
|
|
if ( !smallestTip ) {
|
|
|
|
smallestTip = tip;
|
|
|
|
} else if ( tip->when < smallestTip->when ) {
|
|
|
|
smallestTip = tip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !!smallestTip ) {
|
2009-08-21 14:15:40 +02:00
|
|
|
XP_U32 now = util_getCurSeconds( globals->cGlobals.params->util ) ;
|
|
|
|
if ( now >= smallestTip->when ) {
|
2010-01-25 01:28:30 +01:00
|
|
|
if ( linuxFireTimer( &globals->cGlobals,
|
|
|
|
smallestTip - globals->cGlobals.timerInfo ) ){
|
|
|
|
board_draw( globals->cGlobals.game.board );
|
|
|
|
}
|
2009-08-21 14:15:40 +02:00
|
|
|
} else {
|
|
|
|
XP_LOGF( "skipping timer: now (%ld) < when (%ld)",
|
|
|
|
now, smallestTip->when );
|
|
|
|
}
|
2009-07-10 07:04:04 +02:00
|
|
|
}
|
2009-08-21 14:15:40 +02:00
|
|
|
} /* fireCursesTimer */
|
|
|
|
#endif
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2009-07-10 07:04:04 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
/*
|
|
|
|
* Ok, so this doesn't block yet....
|
|
|
|
*/
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifndef USE_GLIBLOOP
|
2014-12-10 16:47:36 +01:00
|
|
|
/* static XP_Bool */
|
|
|
|
/* blocking_gotEvent( CursesAppGlobals* globals, int* ch ) */
|
|
|
|
/* { */
|
|
|
|
/* XP_Bool result = XP_FALSE; */
|
|
|
|
/* int numEvents, ii; */
|
|
|
|
/* short fdIndex; */
|
|
|
|
/* XP_Bool redraw = XP_FALSE; */
|
|
|
|
|
|
|
|
/* int timeout = figureTimeout( globals ); */
|
|
|
|
/* numEvents = poll( globals->fdArray, globals->fdCount, timeout ); */
|
|
|
|
|
|
|
|
/* if ( timeout != INFINITE_TIMEOUT && numEvents == 0 ) { */
|
|
|
|
/* #ifdef XWFEATURE_RELAY */
|
|
|
|
/* fireCursesTimer( globals ); */
|
|
|
|
/* #endif */
|
|
|
|
/* } else if ( numEvents > 0 ) { */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2014-12-10 16:47:36 +01:00
|
|
|
/* /\* stdin first *\/ */
|
|
|
|
/* if ( (globals->fdArray[FD_STDIN].revents & POLLIN) != 0 ) { */
|
|
|
|
/* int evtCh = wgetch(globals->mainWin); */
|
|
|
|
/* XP_LOGF( "%s: got key: %x", __func__, evtCh ); */
|
|
|
|
/* *ch = evtCh; */
|
|
|
|
/* result = XP_TRUE; */
|
|
|
|
/* --numEvents; */
|
|
|
|
/* } */
|
|
|
|
/* if ( (globals->fdArray[FD_STDIN].revents & ~POLLIN ) ) { */
|
|
|
|
/* XP_LOGF( "some other events set on stdin" ); */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* if ( (globals->fdArray[FD_TIMEEVT].revents & POLLIN) != 0 ) { */
|
|
|
|
/* char ch; */
|
|
|
|
/* if ( 1 != read(globals->fdArray[FD_TIMEEVT].fd, &ch, 1 ) ) { */
|
|
|
|
/* XP_ASSERT(0); */
|
|
|
|
/* } */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* fdIndex = FD_FIRSTSOCKET; */
|
|
|
|
|
|
|
|
/* if ( numEvents > 0 ) { */
|
|
|
|
/* if ( (globals->fdArray[fdIndex].revents & ~POLLIN ) ) { */
|
|
|
|
/* XP_LOGF( "some other events set on socket %d", */
|
|
|
|
/* globals->fdArray[fdIndex].fd ); */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* if ( (globals->fdArray[fdIndex].revents & POLLIN) != 0 ) { */
|
|
|
|
|
|
|
|
/* --numEvents; */
|
|
|
|
|
|
|
|
/* if ( globals->fdArray[fdIndex].fd */
|
|
|
|
/* == globals->csInfo.server.serverSocket ) { */
|
|
|
|
/* /\* It's the listening socket: call platform's accept() */
|
|
|
|
/* wrapper *\/ */
|
|
|
|
/* (*globals->cGlobals.acceptor)( globals->fdArray[fdIndex].fd, */
|
|
|
|
/* globals ); */
|
|
|
|
/* } else { */
|
|
|
|
/* #ifndef XWFEATURE_STANDALONE_ONLY */
|
|
|
|
/* unsigned char buf[1024]; */
|
|
|
|
/* int nBytes; */
|
|
|
|
/* CommsAddrRec addrRec; */
|
|
|
|
/* CommsAddrRec* addrp = NULL; */
|
|
|
|
|
|
|
|
/* /\* It's a normal data socket *\/ */
|
|
|
|
/* switch ( globals->cGlobals.params->conType ) { */
|
|
|
|
/* #ifdef XWFEATURE_RELAY */
|
|
|
|
/* case COMMS_CONN_RELAY: */
|
|
|
|
/* nBytes = linux_relay_receive( &globals->cGlobals, buf, */
|
|
|
|
/* sizeof(buf) ); */
|
|
|
|
/* break; */
|
|
|
|
/* #endif */
|
|
|
|
/* #ifdef XWFEATURE_SMS */
|
|
|
|
/* case COMMS_CONN_SMS: */
|
|
|
|
/* addrp = &addrRec; */
|
|
|
|
/* nBytes = linux_sms_receive( &globals->cGlobals, */
|
|
|
|
/* globals->fdArray[fdIndex].fd, */
|
|
|
|
/* buf, sizeof(buf), addrp ); */
|
|
|
|
/* break; */
|
|
|
|
/* #endif */
|
|
|
|
/* #ifdef XWFEATURE_BLUETOOTH */
|
|
|
|
/* case COMMS_CONN_BT: */
|
|
|
|
/* nBytes = linux_bt_receive( globals->fdArray[fdIndex].fd, */
|
|
|
|
/* buf, sizeof(buf) ); */
|
|
|
|
/* break; */
|
|
|
|
/* #endif */
|
|
|
|
/* default: */
|
|
|
|
/* XP_ASSERT( 0 ); /\* fired *\/ */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* if ( nBytes != -1 ) { */
|
|
|
|
/* XWStreamCtxt* inboundS; */
|
|
|
|
/* redraw = XP_FALSE; */
|
|
|
|
|
|
|
|
/* inboundS = stream_from_msgbuf( &globals->cGlobals, */
|
|
|
|
/* buf, nBytes ); */
|
|
|
|
/* if ( !!inboundS ) { */
|
|
|
|
/* if ( comms_checkIncomingStream( */
|
|
|
|
/* globals->cGlobals.game.comms, */
|
|
|
|
/* inboundS, addrp ) ) { */
|
|
|
|
/* redraw = server_receiveMessage( */
|
|
|
|
/* globals->cGlobals.game.server, inboundS ); */
|
|
|
|
/* } */
|
|
|
|
/* stream_destroy( inboundS ); */
|
|
|
|
/* } */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2014-12-10 16:47:36 +01:00
|
|
|
/* /\* if there's something to draw resulting from the */
|
|
|
|
/* message, we need to give the main loop time to reflect */
|
|
|
|
/* that on the screen before giving the server another */
|
|
|
|
/* shot. So just call the idle proc. *\/ */
|
|
|
|
/* if ( redraw ) { */
|
|
|
|
/* curses_util_requestTime(globals->cGlobals.params->util); */
|
|
|
|
/* } */
|
|
|
|
/* } */
|
|
|
|
/* #else */
|
|
|
|
/* XP_ASSERT(0); /\* no socket activity in standalone game! *\/ */
|
|
|
|
/* #endif /\* #ifndef XWFEATURE_STANDALONE_ONLY *\/ */
|
|
|
|
/* } */
|
|
|
|
/* ++fdIndex; */
|
|
|
|
/* } */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
/* for ( ii = 0; ii < 5; ++ii ) { */
|
|
|
|
/* redraw = server_do( globals->cGlobals.game.server, NULL ) || redraw; */
|
|
|
|
/* } */
|
|
|
|
/* if ( redraw ) { */
|
|
|
|
/* /\* messages change a lot *\/ */
|
|
|
|
/* board_invalAll( globals->cGlobals.game.board ); */
|
|
|
|
/* board_draw( globals->cGlobals.game.board ); */
|
|
|
|
/* } */
|
|
|
|
/* saveGame( globals->cGlobals ); */
|
|
|
|
/* } */
|
|
|
|
/* return result; */
|
|
|
|
/* } /\* blocking_gotEvent *\/ */
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
static void
|
|
|
|
remapKey( int* kp )
|
|
|
|
{
|
|
|
|
/* There's what the manual says I should get, and what I actually do from
|
|
|
|
* a funky M$ keyboard....
|
|
|
|
*/
|
|
|
|
int key = *kp;
|
|
|
|
switch( key ) {
|
|
|
|
case KEY_B2: /* "center of keypad" */
|
|
|
|
key = '\r';
|
|
|
|
break;
|
|
|
|
case KEY_DOWN:
|
|
|
|
case 526:
|
|
|
|
key = 'K';
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
case 523:
|
|
|
|
key = 'J';
|
|
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
|
|
case 524:
|
|
|
|
key = 'H';
|
|
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
|
|
case 525:
|
|
|
|
key = 'L';
|
|
|
|
break;
|
|
|
|
default:
|
2008-02-16 16:49:03 +01:00
|
|
|
if ( key > 0x7F ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
XP_LOGF( "%s(%d): no mapping", __func__, key );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*kp = key;
|
2008-02-16 16:49:03 +01:00
|
|
|
} /* remapKey */
|
2008-02-02 17:56:20 +01:00
|
|
|
|
|
|
|
static void
|
|
|
|
drawMenuLargeOrSmall( CursesAppGlobals* globals, const MenuList* menuList )
|
|
|
|
{
|
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList* lists[] = { g_rootMenuListShow, NULL };
|
2008-02-02 17:56:20 +01:00
|
|
|
#else
|
2008-02-16 16:49:03 +01:00
|
|
|
const MenuList* lists[] = { g_sharedMenuList, menuList, NULL };
|
2008-02-02 17:56:20 +01:00
|
|
|
#endif
|
2008-02-02 18:21:57 +01:00
|
|
|
wclear( globals->menuWin );
|
2008-02-02 17:56:20 +01:00
|
|
|
drawMenuFromList( globals->menuWin, lists, 0, 0 );
|
|
|
|
wrefresh( globals->menuWin );
|
|
|
|
}
|
|
|
|
|
2010-07-09 15:49:32 +02:00
|
|
|
#ifdef KEYBOARD_NAV
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
2006-11-07 06:46:44 +01:00
|
|
|
changeMenuForFocus( CursesAppGlobals* globals, BoardObjectType focussed )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
if ( focussed == OBJ_TRAY ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
globals->menuList = g_trayMenuList;
|
2003-11-01 06:35:29 +01:00
|
|
|
} else if ( focussed == OBJ_BOARD ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
globals->menuList = g_boardMenuList;
|
2003-11-01 06:35:29 +01:00
|
|
|
} else if ( focussed == OBJ_SCORE ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
globals->menuList = g_scoreMenuList;
|
2003-11-01 06:35:29 +01:00
|
|
|
} else {
|
|
|
|
XP_ASSERT(0);
|
|
|
|
}
|
2008-02-02 17:56:20 +01:00
|
|
|
drawMenuLargeOrSmall( globals, globals->menuList );
|
2006-11-07 06:46:44 +01:00
|
|
|
} /* changeMenuForFocus */
|
2010-07-09 15:49:32 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void
|
|
|
|
initClientSocket( CursesAppGlobals* globals, char* serverName )
|
|
|
|
{
|
|
|
|
struct hostent* hostinfo;
|
|
|
|
hostinfo = gethostbyname( serverName );
|
|
|
|
if ( !hostinfo ) {
|
2009-12-14 05:06:26 +01:00
|
|
|
userError( globals, "unable to get host info for %s\n", serverName );
|
2003-11-01 06:35:29 +01:00
|
|
|
} else {
|
2009-12-14 05:06:26 +01:00
|
|
|
char* hostName = inet_ntoa( *(struct in_addr*)hostinfo->h_addr );
|
|
|
|
XP_LOGF( "gethostbyname returned %s", hostName );
|
|
|
|
globals->csInfo.client.serverAddr = inet_addr(hostName);
|
|
|
|
XP_LOGF( "inet_addr returned %lu",
|
|
|
|
globals->csInfo.client.serverAddr );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
} /* initClientSocket */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static VTableMgr*
|
|
|
|
curses_util_getVTManager(XW_UtilCtxt* uc)
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
return globals->cGlobals.params->vtMgr;
|
|
|
|
} /* linux_util_getVTManager */
|
|
|
|
|
2017-02-17 15:23:44 +01:00
|
|
|
static void
|
|
|
|
curses_util_informNeedPassword( XW_UtilCtxt* XP_UNUSED(uc),
|
|
|
|
XP_U16 playerNum,
|
|
|
|
const XP_UCHAR* name )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2017-02-17 15:23:44 +01:00
|
|
|
XP_WARNF( "curses_util_informNeedPassword(num=%d, name=%s", playerNum, name );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* curses_util_askPassword */
|
|
|
|
|
|
|
|
static void
|
2010-06-18 05:35:54 +02:00
|
|
|
curses_util_yOffsetChange( XW_UtilCtxt* XP_UNUSED(uc),
|
2010-10-06 05:57:07 +02:00
|
|
|
XP_U16 XP_UNUSED(maxOffset),
|
|
|
|
XP_U16 XP_UNUSED(oldOffset), XP_U16 XP_UNUSED(newOffset) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2010-10-06 05:57:07 +02:00
|
|
|
/* if ( oldOffset != newOffset ) { */
|
|
|
|
/* XP_WARNF( "curses_util_yOffsetChange(%d,%d,%d) not implemented", */
|
|
|
|
/* maxOffset, oldOffset, newOffset ); */
|
|
|
|
/* } */
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* curses_util_yOffsetChange */
|
|
|
|
|
2016-09-19 18:12:23 +02:00
|
|
|
#ifdef XWFEATURE_TURNCHANGENOTIFY
|
|
|
|
static void
|
|
|
|
curses_util_turnChanged( XW_UtilCtxt* XP_UNUSED(uc), XP_S16 newTurn )
|
|
|
|
{
|
|
|
|
XP_LOGF( "%s(turn=%d)", __func__, newTurn );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-02-20 16:20:19 +01:00
|
|
|
static void
|
|
|
|
curses_util_notifyIllegalWords( XW_UtilCtxt* XP_UNUSED(uc),
|
|
|
|
BadWordInfo* XP_UNUSED(bwi),
|
|
|
|
XP_U16 XP_UNUSED(player),
|
|
|
|
XP_Bool XP_UNUSED(turnLost) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2017-02-20 16:20:19 +01:00
|
|
|
XP_WARNF( "curses_util_notifyIllegalWords not implemented" );
|
|
|
|
} /* curses_util_notifyIllegalWord */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-10-24 11:07:30 +02:00
|
|
|
static void
|
|
|
|
curses_util_remSelected( XW_UtilCtxt* uc )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
XWStreamCtxt* stream;
|
|
|
|
XP_UCHAR* text;
|
|
|
|
|
2013-01-07 15:10:44 +01:00
|
|
|
stream = mem_stream_make( MPPARM(globals->cGlobals.util->mpool)
|
2008-10-24 11:07:30 +02:00
|
|
|
globals->cGlobals.params->vtMgr,
|
|
|
|
globals, CHANNEL_NONE, NULL );
|
|
|
|
board_formatRemainingTiles( globals->cGlobals.game.board, stream );
|
|
|
|
|
|
|
|
text = strFromStream( stream );
|
|
|
|
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* buttons[] = { "Ok" };
|
|
|
|
(void)cursesask( globals, text, VSIZE(buttons), buttons );
|
2008-10-24 11:07:30 +02:00
|
|
|
|
|
|
|
free( text );
|
|
|
|
}
|
|
|
|
|
2008-01-19 17:03:53 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2008-06-30 05:39:27 +02:00
|
|
|
static XWStreamCtxt*
|
2003-11-01 06:35:29 +01:00
|
|
|
curses_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
LaunchParams* params = globals->cGlobals.params;
|
|
|
|
|
2012-11-13 16:23:07 +01:00
|
|
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(uc->mpool) params->vtMgr,
|
|
|
|
&globals->cGlobals, channelNo,
|
|
|
|
sendOnClose );
|
2003-11-01 06:35:29 +01:00
|
|
|
return stream;
|
|
|
|
} /* curses_util_makeStreamFromAddr */
|
2008-01-19 17:03:53 +01:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2013-06-25 03:37:49 +02:00
|
|
|
#ifdef XWFEATURE_CHAT
|
|
|
|
static void
|
2013-07-07 22:17:26 +02:00
|
|
|
curses_util_showChat( XW_UtilCtxt* uc,
|
2015-08-12 16:36:36 +02:00
|
|
|
const XP_UCHAR* const XP_UNUSED_DBG(msg),
|
2017-06-08 22:04:59 +02:00
|
|
|
XP_S16 XP_UNUSED_DBG(from), XP_U32 XP_UNUSED(timestamp) )
|
2013-06-25 03:37:49 +02:00
|
|
|
{
|
2013-07-03 03:30:23 +02:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
|
|
|
globals->nChatsSent = 0;
|
2015-08-12 16:36:36 +02:00
|
|
|
# ifdef DEBUG
|
|
|
|
const XP_UCHAR* name = "<unknown>";
|
|
|
|
if ( 0 <= from ) {
|
|
|
|
CommonGlobals* cGlobals = &globals->cGlobals;
|
|
|
|
name = cGlobals->gi->players[from].name;
|
|
|
|
}
|
|
|
|
XP_LOGF( "%s: got \"%s\" from %s", __func__, msg, name );
|
|
|
|
# endif
|
2013-06-25 03:37:49 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
|
|
|
setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
|
|
|
|
{
|
|
|
|
util->vtable->m_util_userError = curses_util_userError;
|
|
|
|
|
|
|
|
util->vtable->m_util_getVTManager = curses_util_getVTManager;
|
2017-02-17 15:23:44 +01:00
|
|
|
util->vtable->m_util_informNeedPassword = curses_util_informNeedPassword;
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_yOffsetChange = curses_util_yOffsetChange;
|
2016-09-19 18:12:23 +02:00
|
|
|
#ifdef XWFEATURE_TURNCHANGENOTIFY
|
|
|
|
util->vtable->m_util_turnChanged = curses_util_turnChanged;
|
|
|
|
#endif
|
2017-02-20 16:20:19 +01:00
|
|
|
util->vtable->m_util_notifyIllegalWords = curses_util_notifyIllegalWords;
|
2008-10-24 11:07:30 +02:00
|
|
|
util->vtable->m_util_remSelected = curses_util_remSelected;
|
2008-01-19 17:03:53 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_makeStreamFromAddr = curses_util_makeStreamFromAddr;
|
2008-01-19 17:03:53 +01:00
|
|
|
#endif
|
2013-06-25 03:37:49 +02:00
|
|
|
#ifdef XWFEATURE_CHAT
|
|
|
|
util->vtable->m_util_showChat = curses_util_showChat;
|
|
|
|
#endif
|
|
|
|
|
2017-02-17 17:10:09 +01:00
|
|
|
util->vtable->m_util_notifyMove = curses_util_notifyMove;
|
|
|
|
util->vtable->m_util_notifyTrade = curses_util_notifyTrade;
|
2017-02-19 04:16:32 +01:00
|
|
|
util->vtable->m_util_notifyPickTileBlank = curses_util_notifyPickTileBlank;
|
2017-03-10 05:36:14 +01:00
|
|
|
util->vtable->m_util_informNeedPickTiles = curses_util_informNeedPickTiles;
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_trayHiddenChange = curses_util_trayHiddenChange;
|
2011-10-03 01:21:09 +02:00
|
|
|
util->vtable->m_util_informMove = curses_util_informMove;
|
2012-05-14 16:01:02 +02:00
|
|
|
util->vtable->m_util_informUndo = curses_util_informUndo;
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
|
2012-09-04 06:33:46 +02:00
|
|
|
util->vtable->m_util_informNetDict = curses_util_informNetDict;
|
2013-01-08 16:28:30 +01:00
|
|
|
util->vtable->m_util_setIsServer = curses_util_setIsServer;
|
|
|
|
|
2012-10-06 03:51:32 +02:00
|
|
|
#ifdef XWFEATURE_HILITECELL
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_hiliteCell = curses_util_hiliteCell;
|
2012-10-06 03:51:32 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_engineProgressCallback =
|
2006-11-07 06:46:44 +01:00
|
|
|
curses_util_engineProgressCallback;
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_setTimer = curses_util_setTimer;
|
2009-09-21 14:49:08 +02:00
|
|
|
util->vtable->m_util_clearTimer = curses_util_clearTimer;
|
2003-11-01 06:35:29 +01:00
|
|
|
util->vtable->m_util_requestTime = curses_util_requestTime;
|
|
|
|
|
|
|
|
util->closure = globals;
|
|
|
|
} /* setupCursesUtilCallbacks */
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
static CursesMenuHandler
|
2008-02-16 16:49:03 +01:00
|
|
|
getHandlerForKey( const MenuList* list, char ch )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2008-02-02 17:56:20 +01:00
|
|
|
CursesMenuHandler handler = NULL;
|
2003-11-01 06:35:29 +01:00
|
|
|
while ( list->handler != NULL ) {
|
2003-11-16 18:17:04 +01:00
|
|
|
if ( list->key == ch ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
handler = list->handler;
|
|
|
|
break;
|
2003-11-16 18:17:04 +01:00
|
|
|
}
|
|
|
|
++list;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2008-02-02 17:56:20 +01:00
|
|
|
return handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XP_Bool
|
2008-02-16 16:49:03 +01:00
|
|
|
handleKeyEvent( CursesAppGlobals* globals, const MenuList* list, char ch )
|
2008-02-02 17:56:20 +01:00
|
|
|
{
|
|
|
|
CursesMenuHandler handler = getHandlerForKey( list, ch );
|
|
|
|
XP_Bool result = XP_FALSE;
|
|
|
|
if ( !!handler ) {
|
|
|
|
result = (*handler)(globals);
|
|
|
|
}
|
|
|
|
return result;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* handleKeyEvent */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
passKeyToBoard( CursesAppGlobals* globals, char ch )
|
|
|
|
{
|
|
|
|
XP_Bool handled = ch >= 'a' && ch <= 'z';
|
|
|
|
if ( handled ) {
|
2003-11-16 18:17:04 +01:00
|
|
|
ch += 'A' - 'a';
|
2007-01-19 09:20:58 +01:00
|
|
|
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
|
|
|
|
ch, NULL );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
return handled;
|
|
|
|
} /* passKeyToBoard */
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
static void
|
|
|
|
positionSizeStuff( CursesAppGlobals* globals, int width, int height )
|
|
|
|
{
|
2014-01-05 22:04:59 +01:00
|
|
|
CommonGlobals* cGlobals = &globals->cGlobals;
|
|
|
|
BoardCtxt* board = cGlobals->game.board;
|
2013-11-03 21:15:53 +01:00
|
|
|
#ifdef COMMON_LAYOUT
|
2014-01-05 22:04:59 +01:00
|
|
|
|
|
|
|
BoardDims dims;
|
|
|
|
board_figureLayout( board, cGlobals->gi,
|
2016-09-16 05:37:29 +02:00
|
|
|
0, 0, width, height, 100,
|
2014-01-05 22:04:59 +01:00
|
|
|
150, 200, /* percents */
|
2014-01-06 15:54:56 +01:00
|
|
|
width*75/100, 2, 1,
|
2014-01-05 22:04:59 +01:00
|
|
|
XP_FALSE, &dims );
|
|
|
|
board_applyLayout( board, &dims );
|
|
|
|
|
2013-11-03 21:15:53 +01:00
|
|
|
#else
|
|
|
|
XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth;
|
2008-02-02 17:56:20 +01:00
|
|
|
int remWidth = width;
|
2013-07-10 03:10:41 +02:00
|
|
|
int nRows = globals->cGlobals.gi->boardSize;
|
2008-02-02 17:56:20 +01:00
|
|
|
|
2008-02-02 18:21:57 +01:00
|
|
|
cellWidth = CURSES_CELL_WIDTH;
|
|
|
|
cellHt = CURSES_CELL_HT;
|
2010-04-08 06:14:14 +02:00
|
|
|
board_setPos( board, BOARD_OFFSET, BOARD_OFFSET,
|
2011-11-15 05:18:09 +01:00
|
|
|
cellWidth * nRows, cellHt * nRows,
|
2010-06-05 17:10:02 +02:00
|
|
|
cellWidth, XP_FALSE );
|
2010-04-08 06:14:14 +02:00
|
|
|
/* board_setScale( board, cellWidth, cellHt ); */
|
2011-11-15 05:18:09 +01:00
|
|
|
scoreLeft = (cellWidth * nRows);// + BOARD_SCORE_PADDING;
|
|
|
|
remWidth -= cellWidth * nRows;
|
2008-02-02 17:56:20 +01:00
|
|
|
|
|
|
|
/* If the scoreboard will right of the board, put it there. Otherwise try
|
|
|
|
to fit it below the boards. */
|
|
|
|
int tileWidth = 3;
|
|
|
|
int trayWidth = (tileWidth*MAX_TRAY_TILES);
|
|
|
|
int trayLeft = scoreLeft;
|
|
|
|
int trayTop;
|
|
|
|
int trayHt = 4;
|
|
|
|
if ( trayWidth < remWidth ) {
|
|
|
|
trayLeft += XP_MIN(remWidth - trayWidth, BOARD_SCORE_PADDING );
|
|
|
|
trayTop = 8;
|
|
|
|
} else {
|
|
|
|
trayLeft = BOARD_OFFSET;
|
2011-11-15 05:18:09 +01:00
|
|
|
trayTop = BOARD_OFFSET + (cellHt * nRows);
|
2008-02-02 17:56:20 +01:00
|
|
|
if ( trayTop + trayHt > height ) {
|
2011-11-15 05:18:09 +01:00
|
|
|
XP_ASSERT( height > trayTop );
|
2008-02-02 17:56:20 +01:00
|
|
|
trayHt = height - trayTop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
board_setTrayLoc( board, trayLeft, trayTop, (3*MAX_TRAY_TILES)+1,
|
|
|
|
trayHt, 1 );
|
|
|
|
|
|
|
|
scoreWidth = remWidth;
|
|
|
|
if ( scoreWidth > 45 ) {
|
|
|
|
scoreWidth = 45;
|
|
|
|
scoreLeft += (remWidth - scoreWidth) / 2;
|
|
|
|
}
|
|
|
|
board_setScoreboardLoc( board, scoreLeft, 1,
|
|
|
|
scoreWidth, 5, /*4 players + rem*/ XP_FALSE );
|
|
|
|
|
|
|
|
/* no divider -- yet */
|
|
|
|
/* board_setTrayVisible( globals.board, XP_TRUE, XP_FALSE ); */
|
2013-11-03 21:15:53 +01:00
|
|
|
#endif
|
2008-02-02 17:56:20 +01:00
|
|
|
board_invalAll( board );
|
|
|
|
} /* positionSizeStuff */
|
|
|
|
|
2011-09-30 15:32:21 +02:00
|
|
|
static XP_Bool
|
|
|
|
relay_sendNoConn_curses( const XP_U8* msg, XP_U16 len,
|
2015-09-30 15:50:04 +02:00
|
|
|
const XP_UCHAR* XP_UNUSED(msgNo),
|
2011-09-30 15:32:21 +02:00
|
|
|
const XP_UCHAR* relayID, void* closure )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
2011-11-18 04:56:36 +01:00
|
|
|
return storeNoConnMsg( &globals->cGlobals, msg, len, relayID );
|
2011-09-30 15:32:21 +02:00
|
|
|
} /* relay_sendNoConn_curses */
|
|
|
|
|
2009-12-04 09:18:49 +01:00
|
|
|
static void
|
2013-07-01 16:51:38 +02:00
|
|
|
relay_status_curses( void* closure, CommsRelayState state )
|
2009-12-04 09:18:49 +01:00
|
|
|
{
|
2013-07-01 16:51:38 +02:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
|
|
|
globals->commsRelayState = state;
|
2009-12-04 09:18:49 +01:00
|
|
|
XP_LOGF( "%s got status: %s", __func__, CommsRelayState2Str(state) );
|
|
|
|
}
|
|
|
|
|
2009-12-14 05:06:26 +01:00
|
|
|
static void
|
2010-10-29 03:46:07 +02:00
|
|
|
relay_connd_curses( void* XP_UNUSED(closure), XP_UCHAR* const XP_UNUSED(room),
|
2011-05-19 14:51:00 +02:00
|
|
|
XP_Bool XP_UNUSED(reconnect), XP_U16 XP_UNUSED(devOrder),
|
2010-10-29 03:46:07 +02:00
|
|
|
XP_Bool XP_UNUSED_DBG(allHere),
|
2009-12-17 14:09:10 +01:00
|
|
|
XP_U16 XP_UNUSED_DBG(nMissing) )
|
2009-12-14 05:06:26 +01:00
|
|
|
{
|
2013-06-29 05:33:27 +02:00
|
|
|
XP_LOGF( "%s got allHere: %s; nMissing: %d", __func__,
|
|
|
|
allHere?"true":"false", nMissing );
|
2009-12-14 05:06:26 +01:00
|
|
|
}
|
|
|
|
|
2009-12-04 09:18:49 +01:00
|
|
|
static void
|
2010-11-19 07:27:06 +01:00
|
|
|
relay_error_curses( void* XP_UNUSED(closure), XWREASON XP_UNUSED_DBG(relayErr) )
|
2009-12-04 09:18:49 +01:00
|
|
|
{
|
2010-11-19 07:27:06 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
XP_LOGF( "%s(%s)", __func__, XWREASON2Str( relayErr ) );
|
|
|
|
#endif
|
2009-12-04 09:18:49 +01:00
|
|
|
}
|
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
static gboolean
|
2011-10-19 03:52:37 +02:00
|
|
|
handle_stdin( GIOChannel* XP_UNUSED_DBG(source), GIOCondition condition,
|
|
|
|
gpointer data )
|
2011-08-30 05:24:15 +02:00
|
|
|
{
|
|
|
|
if ( 0 != (G_IO_IN & condition) ) {
|
2011-10-19 03:52:37 +02:00
|
|
|
#ifdef DEBUG
|
2011-08-30 05:24:15 +02:00
|
|
|
gint fd = g_io_channel_unix_get_fd( source );
|
|
|
|
XP_ASSERT( 0 == fd );
|
2011-10-19 03:52:37 +02:00
|
|
|
#endif
|
2011-08-30 05:24:15 +02:00
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
|
|
|
int ch = wgetch( globals->mainWin );
|
|
|
|
remapKey( &ch );
|
|
|
|
if (
|
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
|
|
|
handleKeyEvent( globals, g_rootMenuListShow, ch ) ||
|
|
|
|
#endif
|
|
|
|
handleKeyEvent( globals, globals->menuList, ch )
|
|
|
|
|| handleKeyEvent( globals, g_sharedMenuList, ch )
|
|
|
|
|| passKeyToBoard( globals, ch ) ) {
|
|
|
|
if ( g_globals.doDraw ) {
|
|
|
|
board_draw( globals->cGlobals.game.board );
|
|
|
|
globals->doDraw = XP_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-18 16:49:00 +01:00
|
|
|
#ifdef COMMS_XPORT_FLAGSPROC
|
|
|
|
static XP_U32
|
|
|
|
curses_getFlags( void* XP_UNUSED(closure) )
|
|
|
|
{
|
|
|
|
return COMMS_XPORT_FLAGS_HASNOCONN;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-24 16:49:49 +01:00
|
|
|
static void
|
2014-11-05 16:41:20 +01:00
|
|
|
cursesGotBuf( void* closure, const CommsAddrRec* addr,
|
|
|
|
const XP_U8* buf, XP_U16 len )
|
2013-01-24 16:49:49 +01:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
2013-07-12 05:39:10 +02:00
|
|
|
XP_U32 clientToken;
|
|
|
|
XP_ASSERT( sizeof(clientToken) < len );
|
|
|
|
XP_MEMCPY( &clientToken, &buf[0], sizeof(clientToken) );
|
|
|
|
buf += sizeof(clientToken);
|
|
|
|
len -= sizeof(clientToken);
|
|
|
|
|
|
|
|
sqlite3_int64 ignore;
|
|
|
|
XP_U16 seed;
|
|
|
|
rowidFromToken( XP_NTOHL( clientToken ), &ignore, &seed );
|
2014-12-16 01:43:24 +01:00
|
|
|
// XP_ASSERT( seed == comms_getChannelSeed( globals->cGlobals.game.comms ) );
|
2013-07-29 16:30:46 +02:00
|
|
|
if ( seed == comms_getChannelSeed( globals->cGlobals.game.comms ) ) {
|
2014-11-05 16:41:20 +01:00
|
|
|
gameGotBuf( &globals->cGlobals, XP_TRUE, buf, len, addr );
|
2013-07-29 16:30:46 +02:00
|
|
|
} else {
|
|
|
|
XP_LOGF( "%s: dropping packet; meant for a different device",
|
|
|
|
__func__ );
|
|
|
|
}
|
2013-01-24 16:49:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
curses_requestMsgs( gpointer data )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
|
|
|
XP_UCHAR devIDBuf[64] = {0};
|
|
|
|
db_fetch( globals->cGlobals.pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) );
|
|
|
|
if ( '\0' != devIDBuf[0] ) {
|
|
|
|
relaycon_requestMsgs( globals->cGlobals.params, devIDBuf );
|
|
|
|
} else {
|
|
|
|
XP_LOGF( "%s: not requesting messages as don't have relay id", __func__ );
|
|
|
|
}
|
|
|
|
return 0; /* don't run again */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2013-01-25 04:20:35 +01:00
|
|
|
cursesNoticeRcvd( void* closure )
|
2013-01-24 16:49:49 +01:00
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
|
|
|
(void)g_idle_add( curses_requestMsgs, globals );
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:01:16 +02:00
|
|
|
static gboolean
|
|
|
|
keepalive_timer( gpointer data )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
curses_requestMsgs( data );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-01-24 16:49:49 +01:00
|
|
|
static void
|
2013-09-15 06:06:14 +02:00
|
|
|
cursesDevIDReceived( void* closure, const XP_UCHAR* devID,
|
|
|
|
XP_U16 maxInterval )
|
2013-01-24 16:49:49 +01:00
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
2013-01-29 16:42:10 +01:00
|
|
|
CommonGlobals* cGlobals = &globals->cGlobals;
|
|
|
|
sqlite3* pDb = cGlobals->pDb;
|
2013-01-24 16:49:49 +01:00
|
|
|
if ( !!devID ) {
|
|
|
|
XP_LOGF( "%s(devID=%s)", __func__, devID );
|
2013-09-15 06:06:14 +02:00
|
|
|
|
|
|
|
/* If we already have one, make sure it's the same! Else store. */
|
|
|
|
gchar buf[64];
|
|
|
|
XP_Bool have = db_fetch( pDb, KEY_RDEVID, buf, sizeof(buf) );
|
|
|
|
if ( !have ) {
|
|
|
|
db_store( pDb, KEY_RDEVID, devID );
|
|
|
|
} else {
|
|
|
|
XP_ASSERT( 0 == strcmp( buf, devID ) );
|
|
|
|
}
|
2013-08-02 17:01:16 +02:00
|
|
|
(void)g_timeout_add_seconds( maxInterval, keepalive_timer, globals );
|
2013-01-24 16:49:49 +01:00
|
|
|
} else {
|
|
|
|
XP_LOGF( "%s: bad relayid", __func__ );
|
|
|
|
db_remove( pDb, KEY_RDEVID );
|
2013-01-29 16:42:10 +01:00
|
|
|
|
|
|
|
DevIDType typ;
|
|
|
|
const XP_UCHAR* devID = linux_getDevID( cGlobals->params, &typ );
|
2013-09-15 06:06:14 +02:00
|
|
|
relaycon_reg( cGlobals->params, NULL, typ, devID );
|
2013-01-24 16:49:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cursesErrorMsgRcvd( void* closure, const XP_UCHAR* msg )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
|
|
|
|
if ( !!globals->lastErr && 0 == strcmp( globals->lastErr, msg ) ) {
|
|
|
|
XP_LOGF( "skipping error message from relay" );
|
|
|
|
} else {
|
|
|
|
g_free( globals->lastErr );
|
|
|
|
globals->lastErr = g_strdup( msg );
|
2014-01-05 22:04:59 +01:00
|
|
|
const char* buttons[] = { "Ok" };
|
|
|
|
(void)cursesask( globals, msg, VSIZE(buttons), buttons );
|
2013-01-24 16:49:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 03:37:49 +02:00
|
|
|
static gboolean
|
|
|
|
chatsTimerFired( gpointer data )
|
|
|
|
{
|
|
|
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
2013-07-18 16:37:45 +02:00
|
|
|
XWGame* game = &globals->cGlobals.game;
|
|
|
|
GameStateInfo gsi;
|
2013-06-25 03:37:49 +02:00
|
|
|
|
2013-07-18 16:37:45 +02:00
|
|
|
game_getState( game, &gsi );
|
|
|
|
|
|
|
|
if ( gsi.canChat && 3 > globals->nChatsSent ) {
|
2013-06-25 03:37:49 +02:00
|
|
|
XP_UCHAR msg[128];
|
|
|
|
struct tm* timp;
|
|
|
|
struct timeval tv;
|
|
|
|
struct timezone tz;
|
|
|
|
|
|
|
|
gettimeofday( &tv, &tz );
|
|
|
|
timp = localtime( &tv.tv_sec );
|
|
|
|
|
2013-07-18 16:06:20 +02:00
|
|
|
snprintf( msg, sizeof(msg), "%x: Saying hi via chat at %.2d:%.2d:%.2d",
|
|
|
|
comms_getChannelSeed( game->comms ),
|
2013-06-25 03:37:49 +02:00
|
|
|
timp->tm_hour, timp->tm_min, timp->tm_sec );
|
2013-07-02 16:26:32 +02:00
|
|
|
XP_LOGF( "%s: sending \"%s\"", __func__, msg );
|
2015-08-12 16:36:36 +02:00
|
|
|
board_sendChat( game->board, msg );
|
2013-07-03 03:30:23 +02:00
|
|
|
++globals->nChatsSent;
|
2013-06-25 03:37:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-11-05 16:41:20 +01:00
|
|
|
/* static XP_U16 */
|
|
|
|
/* feedBufferCurses( CommonGlobals* cGlobals, sqlite3_int64 rowid, */
|
|
|
|
/* const XP_U8* buf, XP_U16 len, const CommsAddrRec* from ) */
|
|
|
|
/* { */
|
|
|
|
/* gameGotBuf( cGlobals, XP_TRUE, buf, len, from ); */
|
|
|
|
|
|
|
|
/* /\* GtkGameGlobals* globals = findOpenGame( apg, rowid ); *\/ */
|
|
|
|
|
|
|
|
/* /\* if ( !!globals ) { *\/ */
|
|
|
|
/* /\* gameGotBuf( &globals->cGlobals, XP_TRUE, buf, len, from ); *\/ */
|
|
|
|
/* /\* seed = comms_getChannelSeed( globals->cGlobals.game.comms ); *\/ */
|
|
|
|
/* /\* } else { *\/ */
|
|
|
|
/* /\* GtkGameGlobals tmpGlobals; *\/ */
|
|
|
|
/* /\* if ( loadGameNoDraw( &tmpGlobals, apg->params, rowid ) ) { *\/ */
|
|
|
|
/* /\* gameGotBuf( &tmpGlobals.cGlobals, XP_FALSE, buf, len, from ); *\/ */
|
|
|
|
/* /\* seed = comms_getChannelSeed( tmpGlobals.cGlobals.game.comms ); *\/ */
|
|
|
|
/* /\* saveGame( &tmpGlobals.cGlobals ); *\/ */
|
|
|
|
/* /\* } *\/ */
|
|
|
|
/* /\* freeGlobals( &tmpGlobals ); *\/ */
|
|
|
|
/* /\* } *\/ */
|
|
|
|
/* /\* return seed; *\/ */
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
static void
|
|
|
|
smsMsgReceivedCurses( void* closure, const CommsAddrRec* from,
|
|
|
|
XP_U32 XP_UNUSED(gameID),
|
|
|
|
const XP_U8* buf, XP_U16 len )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
CommonGlobals* cGlobals = (CommonGlobals*)closure;
|
|
|
|
gameGotBuf( cGlobals, XP_TRUE, buf, len, from );
|
|
|
|
LOG_RETURN_VOID();
|
|
|
|
/* LaunchParams* params = cGlobals->params; */
|
|
|
|
|
|
|
|
/* sqlite3_int64 rowids[4]; */
|
|
|
|
/* int nRowIDs = VSIZE(rowids); */
|
|
|
|
/* getRowsForGameID( params->pDb, gameID, rowids, &nRowIDs ); */
|
|
|
|
/* for ( int ii = 0; ii < nRowIDs; ++ii ) { */
|
|
|
|
/* gameGotBuf( cGlobals, XP_TRUE, buf, len, from ); */
|
|
|
|
/* // feedBufferCurses( cGlobals, rowids[ii], buf, len, from ); */
|
|
|
|
/* } */
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
void
|
|
|
|
cursesmain( XP_Bool isServer, LaunchParams* params )
|
|
|
|
{
|
2008-02-02 17:56:20 +01:00
|
|
|
int width, height;
|
2013-01-07 15:10:44 +01:00
|
|
|
CommonGlobals* cGlobals = &g_globals.cGlobals;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
memset( &g_globals, 0, sizeof(g_globals) );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
g_globals.loop = g_main_loop_new( NULL, FALSE );
|
|
|
|
#endif
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
g_globals.amServer = isServer;
|
|
|
|
g_globals.cGlobals.params = params;
|
2007-11-26 03:58:25 +01:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2013-12-18 04:54:25 +01:00
|
|
|
g_globals.cGlobals.relaySocket = -1;
|
2007-11-26 03:58:25 +01:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2014-11-05 16:41:20 +01:00
|
|
|
g_globals.cGlobals.socketAdded = curses_socket_added;
|
|
|
|
g_globals.cGlobals.socketAddedClosure = &g_globals;
|
2013-01-24 16:49:49 +01:00
|
|
|
g_globals.cGlobals.onSave = curses_onGameSaved;
|
|
|
|
g_globals.cGlobals.onSaveClosure = &g_globals;
|
|
|
|
|
2008-02-02 17:56:20 +01:00
|
|
|
g_globals.cGlobals.addAcceptor = curses_socket_acceptor;
|
2005-03-19 23:07:53 +01:00
|
|
|
|
2011-01-25 07:20:47 +01:00
|
|
|
g_globals.cGlobals.cp.showBoardArrow = XP_TRUE;
|
|
|
|
g_globals.cGlobals.cp.showRobotScores = params->showRobotScores;
|
|
|
|
g_globals.cGlobals.cp.hideTileValues = params->hideValues;
|
2012-05-05 18:24:41 +02:00
|
|
|
g_globals.cGlobals.cp.skipCommitConfirm = params->skipCommitConfirm;
|
|
|
|
g_globals.cGlobals.cp.sortNewTiles = params->sortNewTiles;
|
|
|
|
g_globals.cGlobals.cp.showColors = params->showColors;
|
|
|
|
g_globals.cGlobals.cp.allowPeek = params->allowPeek;
|
2009-07-10 07:04:04 +02:00
|
|
|
#ifdef XWFEATURE_SLOW_ROBOT
|
2011-01-25 07:20:47 +01:00
|
|
|
g_globals.cGlobals.cp.robotThinkMin = params->robotThinkMin;
|
|
|
|
g_globals.cGlobals.cp.robotThinkMax = params->robotThinkMax;
|
2012-05-03 05:14:42 +02:00
|
|
|
g_globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
2009-07-10 07:04:04 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2013-07-10 03:10:41 +02:00
|
|
|
g_globals.cGlobals.gi = ¶ms->pgi;
|
2013-01-08 05:40:46 +01:00
|
|
|
setupUtil( &g_globals.cGlobals );
|
2013-01-07 15:10:44 +01:00
|
|
|
setupCursesUtilCallbacks( &g_globals, g_globals.cGlobals.util );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2013-01-08 05:40:46 +01:00
|
|
|
initFromParams( &g_globals.cGlobals, params );
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2014-10-15 16:26:18 +02:00
|
|
|
if ( addr_hasType( ¶ms->addr, COMMS_CONN_RELAY ) ) {
|
2008-02-02 17:56:20 +01:00
|
|
|
g_globals.cGlobals.defaultServerName
|
2006-08-26 23:15:20 +02:00
|
|
|
= params->connInfo.relay.relayName;
|
|
|
|
}
|
2006-10-10 03:34:37 +02:00
|
|
|
#endif
|
2011-08-30 05:24:15 +02:00
|
|
|
|
|
|
|
#ifdef USE_GLIBLOOP
|
2013-06-10 15:15:36 +02:00
|
|
|
if ( !params->closeStdin ) {
|
|
|
|
cursesListenOnSocket( &g_globals, 0, handle_stdin );
|
|
|
|
}
|
2012-05-24 04:58:03 +02:00
|
|
|
setOneSecondTimer( &g_globals.cGlobals );
|
2013-01-22 03:57:48 +01:00
|
|
|
|
2013-05-28 01:18:11 +02:00
|
|
|
# ifdef DEBUG
|
|
|
|
int piperesult =
|
|
|
|
# endif
|
|
|
|
pipe( g_globals.quitpipe );
|
2013-05-25 06:19:20 +02:00
|
|
|
XP_ASSERT( piperesult == 0 );
|
|
|
|
cursesListenOnSocket( &g_globals, g_globals.quitpipe[0], handle_quitwrite );
|
2013-07-09 16:18:00 +02:00
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#else
|
2008-02-02 17:56:20 +01:00
|
|
|
cursesListenOnSocket( &g_globals, 0 ); /* stdin */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
int piperesult = pipe( g_globals.timepipe );
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_ASSERT( piperesult == 0 );
|
2005-03-19 23:07:53 +01:00
|
|
|
/* reader pipe */
|
2008-02-02 17:56:20 +01:00
|
|
|
cursesListenOnSocket( &g_globals, g_globals.timepipe[0] );
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2009-07-29 06:29:29 +02:00
|
|
|
|
2009-08-30 17:23:05 +02:00
|
|
|
struct sigaction act = { .sa_handler = SIGINTTERM_handler };
|
2009-07-29 06:29:29 +02:00
|
|
|
sigaction( SIGINT, &act, NULL );
|
2009-08-30 17:23:05 +02:00
|
|
|
sigaction( SIGTERM, &act, NULL );
|
2009-07-29 06:29:29 +02:00
|
|
|
struct sigaction act2 = { .sa_handler = SIGWINCH_handler };
|
|
|
|
sigaction( SIGWINCH, &act2, NULL );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-09-30 15:32:21 +02:00
|
|
|
TransportProcs procs = {
|
|
|
|
.closure = &g_globals,
|
|
|
|
.send = LINUX_SEND,
|
|
|
|
#ifdef COMMS_HEARTBEAT
|
|
|
|
.reset = linux_reset,
|
|
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_RELAY
|
|
|
|
.rstatus = relay_status_curses,
|
|
|
|
.rconnd = relay_connd_curses,
|
|
|
|
.rerror = relay_error_curses,
|
|
|
|
.sendNoConn = relay_sendNoConn_curses,
|
2013-01-18 16:49:00 +01:00
|
|
|
# ifdef COMMS_XPORT_FLAGSPROC
|
|
|
|
.getFlags = curses_getFlags,
|
|
|
|
# endif
|
2011-09-30 15:32:21 +02:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2011-01-25 07:20:47 +01:00
|
|
|
if ( !!params->pipe && !!params->fileName ) {
|
2011-09-30 15:32:21 +02:00
|
|
|
read_pipe_then_close( &g_globals.cGlobals, &procs );
|
|
|
|
} else if ( !!params->nbs && !!params->fileName ) {
|
|
|
|
do_nbs_then_close( &g_globals.cGlobals, &procs );
|
2011-01-25 07:20:47 +01:00
|
|
|
} else {
|
2013-06-25 03:37:49 +02:00
|
|
|
if ( 0 != params->chatsInterval ) {
|
|
|
|
(void)g_timeout_add_seconds( params->chatsInterval, chatsTimerFired,
|
|
|
|
&g_globals );
|
|
|
|
}
|
|
|
|
|
2012-07-27 05:44:33 +02:00
|
|
|
XP_Bool opened = XP_FALSE;
|
2014-01-06 15:40:59 +01:00
|
|
|
initCurses( &g_globals, &width, &height );
|
2008-02-02 17:56:20 +01:00
|
|
|
|
2011-01-25 07:20:47 +01:00
|
|
|
g_globals.draw = (struct CursesDrawCtx*)
|
|
|
|
cursesDrawCtxtMake( g_globals.boardWin );
|
2008-09-18 05:46:27 +02:00
|
|
|
|
2013-09-15 06:06:14 +02:00
|
|
|
XP_Bool idIsNew = XP_TRUE;
|
|
|
|
if ( !!params->dbName ) {
|
|
|
|
sqlite3* pDb = openGamesDB( params->dbName );
|
|
|
|
/* Gross that both need to be set, but they do. */
|
|
|
|
params->pDb = g_globals.cGlobals.pDb = pDb;
|
|
|
|
|
|
|
|
/* Check if we have a local ID already. If we do and it's
|
|
|
|
changed, we care. */
|
|
|
|
idIsNew = linux_setupDevidParams( params );
|
|
|
|
}
|
|
|
|
|
2013-08-08 06:09:48 +02:00
|
|
|
if ( params->useUdp ) {
|
2013-01-24 16:49:49 +01:00
|
|
|
RelayConnProcs procs = {
|
|
|
|
.msgReceived = cursesGotBuf,
|
|
|
|
.msgNoticeReceived = cursesNoticeRcvd,
|
2013-09-15 06:06:14 +02:00
|
|
|
.devIDReceived = cursesDevIDReceived,
|
2013-01-24 16:49:49 +01:00
|
|
|
.msgErrorMsg = cursesErrorMsgRcvd,
|
2014-11-05 16:41:20 +01:00
|
|
|
.socketAdded = curses_socket_added,
|
2013-01-24 16:49:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
relaycon_init( params, &procs, &g_globals,
|
|
|
|
params->connInfo.relay.relayName,
|
|
|
|
params->connInfo.relay.defaultSendPort );
|
2013-09-15 06:06:14 +02:00
|
|
|
|
|
|
|
linux_doInitialReg( params, idIsNew );
|
2013-08-08 06:09:48 +02:00
|
|
|
}
|
|
|
|
|
2014-11-05 16:41:20 +01:00
|
|
|
#ifdef XWFEATURE_SMS
|
|
|
|
gchar buf[32];
|
|
|
|
const gchar* myPhone = params->connInfo.sms.phone;
|
|
|
|
if ( !!myPhone ) {
|
|
|
|
db_store( params->pDb, KEY_SMSPHONE, myPhone );
|
|
|
|
} else if ( !myPhone && db_fetch( params->pDb, KEY_SMSPHONE, buf, VSIZE(buf) ) ) {
|
|
|
|
params->connInfo.sms.phone = myPhone = buf;
|
|
|
|
}
|
|
|
|
XP_U16 myPort = params->connInfo.sms.port;
|
|
|
|
gchar portbuf[8];
|
|
|
|
if ( 0 < myPort ) {
|
|
|
|
sprintf( portbuf, "%d", myPort );
|
|
|
|
db_store( params->pDb, KEY_SMSPORT, portbuf );
|
|
|
|
} else if ( db_fetch( params->pDb, KEY_SMSPORT, portbuf, VSIZE(portbuf) ) ) {
|
|
|
|
params->connInfo.sms.port = myPort = atoi( portbuf );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !!myPhone && myPhone[0] && myPort ) {
|
|
|
|
SMSProcs smsProcs = {
|
|
|
|
.socketAdded = curses_socket_added,
|
|
|
|
.inviteReceived = NULL,
|
|
|
|
.msgReceived = smsMsgReceivedCurses,
|
|
|
|
};
|
|
|
|
linux_sms_init( params, myPhone, myPort, &smsProcs, &g_globals.cGlobals );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-08-08 06:09:48 +02:00
|
|
|
XWStreamCtxt* stream = NULL;
|
|
|
|
if ( !!params->dbName ) {
|
2013-09-15 06:06:14 +02:00
|
|
|
GSList* games = listGames( params->pDb );
|
2013-01-24 16:49:49 +01:00
|
|
|
if ( !!games ) {
|
2013-09-15 06:06:14 +02:00
|
|
|
XP_ASSERT( 1 == g_slist_length(games) ); /* for now */
|
2013-01-24 16:49:49 +01:00
|
|
|
stream = mem_stream_make( MEMPOOL params->vtMgr,
|
|
|
|
&g_globals.cGlobals, CHANNEL_NONE,
|
|
|
|
NULL );
|
|
|
|
sqlite3_int64 selRow = *(sqlite3_int64*)games->data;
|
2015-02-10 04:15:43 +01:00
|
|
|
/* XP_UCHAR buf[32]; */
|
|
|
|
/* XP_SNPRINTF( buf, sizeof(buf), "%lld", selRow ); */
|
|
|
|
mpool_setTag( MEMPOOL params->dbName );
|
2013-09-15 06:06:14 +02:00
|
|
|
if ( loadGame( stream, params->pDb, selRow ) ) {
|
2013-01-24 16:49:49 +01:00
|
|
|
g_globals.cGlobals.selRow = selRow;
|
|
|
|
} else {
|
|
|
|
stream_destroy( stream );
|
|
|
|
stream = NULL;
|
|
|
|
}
|
|
|
|
g_slist_free( games );
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if ( !!params->fileName && file_exists( params->fileName ) ) {
|
2015-02-10 04:15:43 +01:00
|
|
|
mpool_setTag( MEMPOOL "file" );
|
2011-01-25 07:20:47 +01:00
|
|
|
stream = streamFromFile( &g_globals.cGlobals, params->fileName,
|
|
|
|
&g_globals );
|
2012-07-29 17:37:08 +02:00
|
|
|
#ifdef USE_SQLITE
|
2012-07-27 05:44:33 +02:00
|
|
|
} else if ( !!params->dbFileName && file_exists( params->dbFileName ) ) {
|
2015-02-10 04:15:43 +01:00
|
|
|
XP_UCHAR buf[32];
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf), "%d", params->dbFileID );
|
|
|
|
mpool_setTag( MEMPOOL buf );
|
2012-07-27 05:44:33 +02:00
|
|
|
stream = streamFromDB( &g_globals.cGlobals, &g_globals );
|
2012-07-29 17:37:08 +02:00
|
|
|
#endif
|
2012-07-27 05:44:33 +02:00
|
|
|
}
|
2008-09-18 05:46:27 +02:00
|
|
|
|
2013-01-26 20:56:20 +01:00
|
|
|
if ( NULL == cGlobals->dict ) {
|
|
|
|
if ( !!stream ) {
|
2013-01-08 05:40:46 +01:00
|
|
|
cGlobals->dict = makeDictForStream( cGlobals, stream );
|
2013-01-26 20:56:20 +01:00
|
|
|
} else {
|
|
|
|
cGlobals->dict =
|
|
|
|
linux_dictionary_make( MEMPOOL params,
|
2013-07-10 03:10:41 +02:00
|
|
|
cGlobals->gi->dictName, XP_TRUE );
|
2013-01-08 05:40:46 +01:00
|
|
|
}
|
2013-01-26 20:56:20 +01:00
|
|
|
}
|
2013-07-10 03:10:41 +02:00
|
|
|
cGlobals->gi->dictLang = dict_getLangCode( cGlobals->dict );
|
2013-01-26 20:56:20 +01:00
|
|
|
|
|
|
|
if ( !!stream ) {
|
2013-01-07 15:10:44 +01:00
|
|
|
(void)game_makeFromStream( MEMPOOL stream, &cGlobals->game,
|
2013-07-10 03:10:41 +02:00
|
|
|
cGlobals->gi, cGlobals->dict,
|
2013-01-24 16:49:49 +01:00
|
|
|
&cGlobals->dicts, cGlobals->util,
|
2011-01-25 07:20:47 +01:00
|
|
|
(DrawCtx*)g_globals.draw,
|
|
|
|
&g_globals.cGlobals.cp, &procs );
|
2008-09-18 05:46:27 +02:00
|
|
|
|
2011-01-25 07:20:47 +01:00
|
|
|
stream_destroy( stream );
|
2013-07-10 03:10:41 +02:00
|
|
|
if ( !isServer && cGlobals->gi->serverRole == SERVER_ISSERVER ) {
|
2011-01-25 07:20:47 +01:00
|
|
|
isServer = XP_TRUE;
|
|
|
|
}
|
2012-07-27 05:44:33 +02:00
|
|
|
opened = XP_TRUE;
|
|
|
|
}
|
|
|
|
if ( !opened ) {
|
2013-07-10 03:10:41 +02:00
|
|
|
game_makeNewGame( MEMPOOL &cGlobals->game, cGlobals->gi,
|
2013-01-07 15:10:44 +01:00
|
|
|
cGlobals->util, (DrawCtx*)g_globals.draw,
|
2014-12-22 02:40:00 +01:00
|
|
|
&g_globals.cGlobals.cp, &procs,
|
2014-12-29 16:39:28 +01:00
|
|
|
params->gameSeed );
|
2013-01-24 16:49:49 +01:00
|
|
|
g_globals.cGlobals.selRow = -1;
|
|
|
|
saveGame( &g_globals.cGlobals );
|
2010-09-20 13:55:35 +02:00
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-01-19 17:03:53 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2013-01-07 15:10:44 +01:00
|
|
|
if ( cGlobals->game.comms ) {
|
2011-01-25 07:20:47 +01:00
|
|
|
CommsAddrRec addr = {0};
|
2006-09-19 05:39:08 +02:00
|
|
|
|
2014-10-15 16:26:18 +02:00
|
|
|
CommsConnType typ;
|
|
|
|
for ( XP_U32 st = 0; addr_iter( ¶ms->addr, &typ, &st ); ) {
|
|
|
|
switch( typ ) {
|
2008-01-19 17:03:53 +01:00
|
|
|
# ifdef XWFEATURE_RELAY
|
2014-10-15 16:26:18 +02:00
|
|
|
case COMMS_CONN_RELAY:
|
|
|
|
addr_addType( &addr, COMMS_CONN_RELAY );
|
|
|
|
addr.u.ip_relay.ipAddr = 0; /* ??? */
|
|
|
|
addr.u.ip_relay.port = params->connInfo.relay.defaultSendPort;
|
|
|
|
addr.u.ip_relay.seeksPublicRoom = params->connInfo.relay.seeksPublicRoom;
|
|
|
|
addr.u.ip_relay.advertiseRoom = params->connInfo.relay.advertiseRoom;
|
|
|
|
XP_STRNCPY( addr.u.ip_relay.hostName, params->connInfo.relay.relayName,
|
|
|
|
sizeof(addr.u.ip_relay.hostName) - 1 );
|
|
|
|
XP_STRNCPY( addr.u.ip_relay.invite, params->connInfo.relay.invite,
|
|
|
|
sizeof(addr.u.ip_relay.invite) - 1 );
|
|
|
|
break;
|
2008-01-19 17:03:53 +01:00
|
|
|
# endif
|
2009-01-13 14:33:56 +01:00
|
|
|
# ifdef XWFEATURE_SMS
|
2014-10-15 16:26:18 +02:00
|
|
|
case COMMS_CONN_SMS:
|
|
|
|
addr_addType( &addr, COMMS_CONN_SMS );
|
|
|
|
XP_STRNCPY( addr.u.sms.phone, params->connInfo.sms.phone,
|
|
|
|
sizeof(addr.u.sms.phone) - 1 );
|
|
|
|
addr.u.sms.port = params->connInfo.sms.port;
|
|
|
|
break;
|
2009-01-13 14:33:56 +01:00
|
|
|
# endif
|
2008-01-19 17:03:53 +01:00
|
|
|
# ifdef XWFEATURE_BLUETOOTH
|
2014-10-15 16:26:18 +02:00
|
|
|
case COMMS_CONN_BT:
|
|
|
|
addr_addType( &addr, COMMS_CONN_BT );
|
|
|
|
XP_ASSERT( sizeof(addr.u.bt.btAddr)
|
|
|
|
>= sizeof(params->connInfo.bt.hostAddr));
|
|
|
|
XP_MEMCPY( &addr.u.bt.btAddr, ¶ms->connInfo.bt.hostAddr,
|
|
|
|
sizeof(params->connInfo.bt.hostAddr) );
|
|
|
|
break;
|
2008-01-19 17:03:53 +01:00
|
|
|
# endif
|
2014-10-15 16:26:18 +02:00
|
|
|
#ifdef XWFEATURE_DIRECTIP
|
|
|
|
case COMMS_CONN_IP_DIRECT:
|
|
|
|
addr_addType( &addr, COMMS_CONN_IP_DIRECT );
|
|
|
|
XP_MEMCPY( addr.u.ip.hostName_ip, ¶ms->connInfo.ip.hostName,
|
|
|
|
sizeof(addr.u.ip.hostName_ip) );
|
|
|
|
addr.u.ip.port_ip = params->connInfo.ip.hostPort;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2011-01-25 07:20:47 +01:00
|
|
|
}
|
2013-01-07 15:10:44 +01:00
|
|
|
comms_setAddr( cGlobals->game.comms, &addr );
|
2006-09-19 05:39:08 +02:00
|
|
|
}
|
2008-01-19 17:03:53 +01:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2013-01-07 15:10:44 +01:00
|
|
|
model_setDictionary( cGlobals->game.model, cGlobals->dict );
|
|
|
|
setSquareBonuses( cGlobals );
|
2011-01-25 07:20:47 +01:00
|
|
|
positionSizeStuff( &g_globals, width, height );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-01-19 17:03:53 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2011-01-25 07:20:47 +01:00
|
|
|
/* send any events that need to get off before the event loop begins */
|
2015-08-19 15:05:18 +02:00
|
|
|
if ( !!cGlobals->game.comms && !isServer ) {
|
2014-09-14 22:42:11 +02:00
|
|
|
(void)server_initClientConnection( cGlobals->game.server,
|
|
|
|
mem_stream_make( MEMPOOL
|
|
|
|
params->vtMgr,
|
|
|
|
cGlobals,
|
|
|
|
(XP_PlayerAddr)0,
|
|
|
|
sendOnClose ) );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2008-01-19 17:03:53 +01:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-12-22 03:45:05 +01:00
|
|
|
server_do( g_globals.cGlobals.game.server );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-01-25 07:20:47 +01:00
|
|
|
g_globals.menuList = g_boardMenuList;
|
|
|
|
drawMenuLargeOrSmall( &g_globals, g_boardMenuList );
|
|
|
|
board_draw( g_globals.cGlobals.game.board );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2011-08-30 05:24:15 +02:00
|
|
|
#ifdef USE_GLIBLOOP
|
|
|
|
g_main_loop_run( g_globals.loop );
|
|
|
|
#else
|
2011-01-25 07:20:47 +01:00
|
|
|
while ( !g_globals.timeToExit ) {
|
|
|
|
int ch = 0;
|
|
|
|
if ( blocking_gotEvent( &g_globals, &ch ) ) {
|
|
|
|
remapKey( &ch );
|
|
|
|
if (
|
2008-02-02 17:56:20 +01:00
|
|
|
#ifdef CURSES_SMALL_SCREEN
|
2011-01-25 07:20:47 +01:00
|
|
|
handleKeyEvent( &g_globals, g_rootMenuListShow, ch ) ||
|
2008-02-02 17:56:20 +01:00
|
|
|
#endif
|
2011-01-25 07:20:47 +01:00
|
|
|
handleKeyEvent( &g_globals, g_globals.menuList, ch )
|
|
|
|
|| handleKeyEvent( &g_globals, g_sharedMenuList, ch )
|
|
|
|
|| passKeyToBoard( &g_globals, ch ) ) {
|
|
|
|
if ( g_globals.doDraw ) {
|
|
|
|
board_draw( g_globals.cGlobals.game.board );
|
|
|
|
g_globals.doDraw = XP_FALSE;
|
|
|
|
}
|
2008-02-02 17:56:20 +01:00
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
}
|
2011-08-30 05:24:15 +02:00
|
|
|
#endif
|
2011-01-25 07:20:47 +01:00
|
|
|
}
|
2013-01-20 07:53:25 +01:00
|
|
|
if ( !!g_globals.cGlobals.game.comms ) {
|
|
|
|
comms_stop( g_globals.cGlobals.game.comms );
|
|
|
|
}
|
2012-09-10 16:31:45 +02:00
|
|
|
saveGame( &g_globals.cGlobals );
|
2010-09-20 13:55:35 +02:00
|
|
|
|
2014-03-12 05:59:53 +01:00
|
|
|
game_dispose( &g_globals.cGlobals.game );
|
2013-07-10 03:10:41 +02:00
|
|
|
gi_disposePlayerInfo( MEMPOOL cGlobals->gi );
|
2014-03-12 05:59:53 +01:00
|
|
|
dict_unref( cGlobals->dict );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2009-01-13 14:33:56 +01:00
|
|
|
#ifdef XWFEATURE_BLUETOOTH
|
|
|
|
linux_bt_close( &g_globals.cGlobals );
|
|
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_SMS
|
2013-12-13 06:08:25 +01:00
|
|
|
// linux_sms_close( &g_globals.cGlobals );
|
2009-01-13 14:33:56 +01:00
|
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_IP_DIRECT
|
|
|
|
linux_udp_close( &g_globals.cGlobals );
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
endwin();
|
2013-01-08 05:40:46 +01:00
|
|
|
|
2013-01-24 17:08:53 +01:00
|
|
|
if ( !!params->dbName ) {
|
|
|
|
closeGamesDB( g_globals.cGlobals.pDb );
|
|
|
|
}
|
|
|
|
relaycon_cleanup( params );
|
|
|
|
|
2014-11-05 16:41:20 +01:00
|
|
|
linux_sms_cleanup( params );
|
|
|
|
|
2013-01-08 05:40:46 +01:00
|
|
|
linux_util_vt_destroy( g_globals.cGlobals.util );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* cursesmain */
|
|
|
|
#endif /* PLATFORM_NCURSES */
|