make bad phonies alert non-blocking

Continue conversion of alerts that required blocking the JNI thread. Now
board_commitTurn() takes a second boolean indicating whether phonies
found have been approved by user. Common code informs user, and if he
approves client code calls board_commitTurn() again. In case where
turn's lost there's no call to make back, but there's the undesirable
change that if a robot moves next its move will be reported on top of
the turn-lost alert. Ideally new alerts would appear under, not on top
of, those that have not yet been dismissed.
This commit is contained in:
Eric House 2017-02-20 07:20:19 -08:00
parent 42aef7b85c
commit c271202faa
17 changed files with 133 additions and 129 deletions

View file

@ -275,7 +275,7 @@ public class BoardDelegate extends DelegateBase
lstnr = new OnClickListener() {
public void onClick( DialogInterface dialog,
int whichButton ) {
handleViaThread( JNICmd.CMD_COMMIT_TRUE );
handleViaThread( JNICmd.CMD_COMMIT, true, true );
}
};
dialog = ab.setMessage( msg )
@ -286,8 +286,21 @@ public class BoardDelegate extends DelegateBase
}
break;
case DLG_BADWORDS_BLK:
checkBlocking();
case NOTIFY_BADWORDS: {
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int bx ) {
handleViaThread( JNICmd.CMD_COMMIT, true, false );
}
};
dialog = ab.setTitle( R.string.phonies_found_title )
.setMessage( (String)params[0] )
.setPositiveButton( R.string.button_yes, lstnr )
.setNegativeButton( android.R.string.cancel, null )
.create();
}
break;
case DLG_BADWORDS:
case DLG_SCORES: {
int title = (Integer)params[0];
String msg = (String)params[1];
@ -917,7 +930,7 @@ public class BoardDelegate extends DelegateBase
break;
case R.id.board_menu_trade_commit:
cmd = JNICmd.CMD_COMMIT_FALSE;
cmd = JNICmd.CMD_COMMIT;
break;
case R.id.board_menu_trade_cancel:
cmd = JNICmd.CMD_CANCELTRADE;
@ -1045,7 +1058,7 @@ public class BoardDelegate extends DelegateBase
Utils.launchSettings( m_activity );
break;
case COMMIT_ACTION:
cmd = JNICmd.CMD_COMMIT_FALSE;
cmd = JNICmd.CMD_COMMIT;
break;
case SHOW_EXPL_ACTION:
showToast( m_toastStr );
@ -1240,7 +1253,7 @@ public class BoardDelegate extends DelegateBase
public void onClick( View view )
{
if ( view == m_exchCommmitButton ) {
handleViaThread( JNICmd.CMD_COMMIT_FALSE );
handleViaThread( JNICmd.CMD_COMMIT );
} else if ( view == m_exchCancelButton ) {
handleViaThread( JNICmd.CMD_CANCELTRADE );
}
@ -2034,33 +2047,21 @@ public class BoardDelegate extends DelegateBase
handleViaThread( JNICmd.CMD_POST_OVER );
}
// public void yOffsetChange( int maxOffset, int oldOffset, int newOffset )
// {
// DbgUtils.logf( "yOffsetChange(maxOffset=%d)", maxOffset );
// m_view.setVerticalScrollBarEnabled( maxOffset > 0 );
// }
@Override
public boolean warnIllegalWord( String dict, String[] words, int turn,
public void notifyIllegalWords( String dict, String[] words, int turn,
boolean turnLost )
{
boolean accept = turnLost;
String wordsString = TextUtils.join( ", ", words );
String message =
getString( R.string.ids_badwords_fmt, wordsString, dict );
if ( turnLost ) {
waitBlockingDialog( DlgID.DLG_BADWORDS_BLK, 0, R.string.badwords_title,
showDialogFragment( DlgID.DLG_BADWORDS, R.string.badwords_title,
message + getString( R.string.badwords_lost ) );
} else {
Assert.fail();
// String dlgBytes = message + getString( R.string.badwords_accept );
// accept = 0 != waitBlockingDialog( DlgID.QUERY_REQUEST_BLK, 0,
// R.string.query_title,
// dlgBytes );
String msg = message + getString( R.string.badwords_accept );
showDialogFragment( DlgID.NOTIFY_BADWORDS, msg );
}
return accept;
}
// Let's have this block in case there are multiple messages. If

View file

@ -57,7 +57,8 @@ public enum DlgID {
, WARN_NODICT
, WARN_NODICT_NEW
, WARN_NODICT_SUBST
, DLG_BADWORDS_BLK
, DLG_BADWORDS
, NOTIFY_BADWORDS
, QUERY_MOVE
, QUERY_TRADE
, PICK_TILE_REQUESTBLANK

View file

@ -71,8 +71,7 @@ public class JNIThread extends Thread {
CMD_KEYDOWN,
CMD_KEYUP,
CMD_TIMER_FIRED,
CMD_COMMIT_FALSE,
CMD_COMMIT_TRUE,
CMD_COMMIT,
CMD_JUGGLE,
CMD_FLIP,
CMD_TOGGLE_TRAY,
@ -544,13 +543,14 @@ public class JNIThread extends Thread {
draw = processKeyEvent( elem.m_cmd, (XwJNI.XP_Key)args[0], barr );
break;
case CMD_COMMIT_FALSE:
draw = XwJNI.board_commitTurn( m_jniGamePtr, false );
case CMD_COMMIT:
boolean phoniesConfirmed = args.length < 1
? false : (Boolean)args[0];
boolean turnConfirmed = args.length < 2
? false : (Boolean)args[1];
draw = XwJNI.board_commitTurn( m_jniGamePtr, phoniesConfirmed,
turnConfirmed );
break;
case CMD_COMMIT_TRUE:
draw = XwJNI.board_commitTurn( m_jniGamePtr, true );
break;
case CMD_JUGGLE:
draw = XwJNI.board_juggleTray( m_jniGamePtr );
break;

View file

@ -141,7 +141,7 @@ public interface UtilCtxt {
// Don't need this unless we have a scroll thumb to indicate position
//void yOffsetChange( int maxOffset, int oldOffset, int newOffset );
boolean warnIllegalWord( String dict, String[] words, int turn,
void notifyIllegalWords( String dict, String[] words, int turn,
boolean turnLost );
void showChat( String msg, int fromIndx, String fromName );

View file

@ -282,11 +282,10 @@ public class UtilCtxtImpl implements UtilCtxt {
subclassOverride( "notifyGameOver" );
}
public boolean warnIllegalWord( String dict, String[] words, int turn,
public void notifyIllegalWords( String dict, String[] words, int turn,
boolean turnLost )
{
subclassOverride( "warnIllegalWord" );
return false;
subclassOverride( "notifyIllegalWords" );
}
// These need to go into some sort of chat DB, not dropped.

View file

@ -299,7 +299,9 @@ public class XwJNI {
public static native boolean board_showTray( GamePtr gamePtr );
public static native boolean board_toggle_showValues( GamePtr gamePtr );
public static native boolean board_commitTurn( GamePtr gamePtr,
boolean alreadyConfirmed );
boolean phoniesConfirmed,
boolean turnConfirmed );
public static native boolean board_flip( GamePtr gamePtr );
public static native boolean board_replaceTiles( GamePtr gamePtr );
public static native int board_getSelPlayer( GamePtr gamePtr );

View file

@ -897,6 +897,8 @@
found in the word list) -->
<string name="default_phonies">Handle phonies</string>
<string name="phonies_found_title">Phonies found</string>
<!-- default number of minutes on timer for new games -->
<string name="initial_player_minutes">Timer minutes per player</string>

View file

@ -454,25 +454,23 @@ and_util_getUserQuantityString( XW_UtilCtxt* uc, XP_U16 stringCode, XP_U16 quant
return result;
}
static XP_Bool
and_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost )
static void
and_util_notifyIllegalWords( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost )
{
jboolean result = XP_FALSE;
UTIL_CBK_HEADER("warnIllegalWord",
"(Ljava/lang/String;[Ljava/lang/String;IZ)Z" );
UTIL_CBK_HEADER("notifyIllegalWords",
"(Ljava/lang/String;[Ljava/lang/String;IZ)V" );
XP_ASSERT( bwi->nWords > 0 );
if ( bwi->nWords > 0 ) {
jobjectArray jwords = makeStringArray( env, bwi->nWords,
(const XP_UCHAR**)bwi->words );
XP_ASSERT( !!bwi->dictName );
jstring jname = (*env)->NewStringUTF( env, bwi->dictName );
result = (*env)->CallBooleanMethod( env, util->jutil, mid,
jname, jwords, turn, turnLost );
(*env)->CallVoidMethod( env, util->jutil, mid,
jname, jwords, turn, turnLost );
deleteLocalRefs( env, jwords, jname, DELETE_NO_REF );
}
UTIL_CBK_TAIL();
return result;
}
#ifdef XWFEATURE_CHAT
@ -732,7 +730,7 @@ makeUtil( MPFORMAL EnvThreadInfo* ti, jobject jutil, CurGameInfo* gi,
SET_PROC(makeEmptyDict);
SET_PROC(getUserString);
SET_PROC(getUserQuantityString);
SET_PROC(warnIllegalWord);
SET_PROC(notifyIllegalWords);
#ifdef XWFEATURE_CHAT
SET_PROC(showChat);
#endif

View file

@ -1282,11 +1282,13 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1toggle_1showValues
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1commitTurn
(JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean alreadyConfirmed)
(JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean phoniesConfirmed,
jboolean turnConfirmed)
{
jboolean result;
XWJNI_START();
result = board_commitTurn( state->game.board, alreadyConfirmed );
result = board_commitTurn( state->game.board, phoniesConfirmed,
turnConfirmed );
XWJNI_END();
return result;
}

View file

@ -984,8 +984,14 @@ hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
#endif
#endif
typedef struct _BadWordList {
BadWordInfo bwi;
XP_UCHAR buf[256];
XP_U16 index;
} BadWordList;
static void
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal,
saveBadWords( const XP_UCHAR* word, XP_Bool isLegal,
const DictionaryCtxt* XP_UNUSED(dict),
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei),
@ -993,22 +999,14 @@ warnBadWords( const XP_UCHAR* word, XP_Bool isLegal,
#endif
void* closure )
{
XP_Bool ok = XP_TRUE;
if ( !isLegal ) {
BadWordInfo bwi = {0};
BoardCtxt* board = (BoardCtxt*)closure;
XP_S16 turn = server_getCurrentTurn( board->server, NULL );
bwi.nWords = 1;
bwi.words[0] = word;
bwi.dictName =
dict_getShortName( model_getPlayerDict( board->model, turn ) );
ok = !board->badWordRejected
&& util_warnIllegalWord( board->util, &bwi, turn, XP_FALSE );
board->badWordRejected = !ok || board->badWordRejected;
BadWordList* bwlp = (BadWordList*)closure;
bwlp->bwi.words[bwlp->bwi.nWords] = &bwlp->buf[bwlp->index];
XP_STRCAT( &bwlp->buf[bwlp->index], word );
bwlp->index += XP_STRLEN(word) + 1;
++bwlp->bwi.nWords;
}
} /* warnBadWords */
} /* saveBadWords */
static void
boardNotifyTrade( BoardCtxt* board, const TrayTileSet* tiles )
@ -1025,7 +1023,8 @@ boardNotifyTrade( BoardCtxt* board, const TrayTileSet* tiles )
}
XP_Bool
board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed )
board_commitTurn( BoardCtxt* board, XP_Bool phoniesConfirmed,
XP_Bool turnConfirmed /* includes trade */ )
{
XP_Bool result = XP_FALSE;
const XP_S16 turn = server_getCurrentTurn( board->server, NULL );
@ -1038,7 +1037,7 @@ board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed )
} else if ( 0 == model_getNumTilesTotal( board->model, turn ) ) {
/* game's over but still undoable so turn hasn't changed; do
nothing */
} else if ( alreadyConfirmed || checkRevealTray( board ) ) {
} else if ( phoniesConfirmed || turnConfirmed || checkRevealTray( board ) ) {
if ( pti->tradeInProgress ) {
TileBit traySelBits = pti->traySelBits;
result = XP_TRUE; /* there's at least the window to clean up
@ -1049,7 +1048,7 @@ board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed )
} else {
TrayTileSet selTiles;
getSelTiles( board, traySelBits, &selTiles );
if ( alreadyConfirmed ) {
if ( turnConfirmed ) {
/* server_commitTrade() changes selPlayer, so board_endTrade
must be called first() */
(void)board_endTrade( board );
@ -1061,11 +1060,10 @@ board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed )
}
} else {
XWStreamCtxt* stream = NULL;
XP_Bool legal = alreadyConfirmed;
XP_Bool legal = turnConfirmed;
BadWordList bwl = {0};
if ( !legal ) {
WordNotifierInfo info;
XP_Bool warn;
stream = mem_stream_make( MPPARM(board->mpool)
util_getVTManager(board->util), NULL,
CHANNEL_NONE, (MemStreamCloseCallback)NULL );
@ -1074,27 +1072,30 @@ board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed )
STR_COMMIT_CONFIRM);
stream_catString( stream, str );
warn = board->util->gameInfo->phoniesAction == PHONIES_WARN;
board->badWordRejected = XP_FALSE;
info.proc = warnBadWords;
info.closure = board;
XP_Bool warn = board->util->gameInfo->phoniesAction == PHONIES_WARN;
WordNotifierInfo info;
if ( warn ) {
info.proc = saveBadWords;
info.closure = &bwl;
}
legal = model_checkMoveLegal( board->model, turn, stream,
warn? &info:(WordNotifierInfo*)NULL);
warn? &info:(WordNotifierInfo*)NULL);
}
if ( !legal || board->badWordRejected ) {
result = XP_FALSE;
if ( 0 < bwl.bwi.nWords && !phoniesConfirmed ) {
bwl.bwi.dictName =
dict_getShortName( model_getPlayerDict( board->model, turn ) );
util_notifyIllegalWords( board->util, &bwl.bwi, turn, XP_FALSE );
} else {
/* Hide the tray so no peeking. Leave it hidden even if user
cancels as otherwise another player could get around
passwords and peek at tiles. */
if ( !alreadyConfirmed
if ( !turnConfirmed
&& gi_countLocalPlayers( board->gi, XP_TRUE ) > 1 ) {
result = board_hideTray( board );
}
if ( board->skipCommitConfirm || alreadyConfirmed ) {
if ( board->skipCommitConfirm || turnConfirmed ) {
result = server_commitMove( board->server ) || result;
/* invalidate all tiles in case we'll be drawing this tray
again rather than some other -- as is the case in a

View file

@ -176,7 +176,8 @@ XP_Bool board_setBlankValue( BoardCtxt* board, XP_U16 XP_UNUSED(player),
void board_resetEngine( BoardCtxt* board );
XP_Bool board_commitTurn( BoardCtxt* board, XP_Bool alreadyConfirmed );
XP_Bool board_commitTurn( BoardCtxt* board, XP_Bool phoniesConfirmed,
XP_Bool turnConfirmed );
void board_pushTimerSave( BoardCtxt* board );
void board_popTimerSave( BoardCtxt* board );

View file

@ -169,7 +169,6 @@ struct BoardCtxt {
XP_Bool showGrid;
XP_Bool gameOver;
XP_Bool leftHanded;
XP_Bool badWordRejected;
XP_Bool timerPending;
XP_Bool disableArrow;
XP_Bool hideValsInTray;

View file

@ -1618,7 +1618,7 @@ badWordMoveUndoAndTellUser( ServerCtxt* server, BadWordInfo* bwi )
model_rejectPreviousMove( model, server->pool, &turn );
util_warnIllegalWord( server->vol.util, bwi, turn, XP_TRUE );
util_notifyIllegalWords( server->vol.util, bwi, turn, XP_TRUE );
} /* badWordMoveUndoAndTellUser */
EngineCtxt*

View file

@ -460,7 +460,7 @@ handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
}
#endif
} else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */
result = board_commitTurn( board, XP_FALSE );
result = board_commitTurn( board, XP_FALSE, XP_FALSE );
#if defined XWFEATURE_TRAYUNDO_ALL
} else if ( index < 0 ) { /* other empty area */
/* it better be true */

View file

@ -159,7 +159,7 @@ typedef struct UtilVtable {
XP_U16 stringCode,
XP_U16 quantity );
XP_Bool (*m_util_warnIllegalWord)( XW_UtilCtxt* uc, BadWordInfo* bwi,
void (*m_util_notifyIllegalWords)( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost );
void (*m_util_remSelected)(XW_UtilCtxt* uc);
@ -302,8 +302,8 @@ struct XW_UtilCtxt {
#define util_getUserQuantityString( uc, c, q ) \
(uc)->vtable->m_util_getUserQuantityString((uc),(c),(q))
#define util_warnIllegalWord( uc, w, p, b ) \
(uc)->vtable->m_util_warnIllegalWord((uc),(w),(p),(b))
#define util_notifyIllegalWords( uc, w, p, b ) \
(uc)->vtable->m_util_notifyIllegalWords((uc),(w),(p),(b))
#define util_remSelected( uc ) \
(uc)->vtable->m_util_remSelected((uc))

View file

@ -620,7 +620,7 @@ static XP_Bool
handleCommit( CursesAppGlobals* globals )
{
globals->doDraw = board_commitTurn( globals->cGlobals.game.board,
XP_FALSE );
XP_FALSE, XP_FALSE );
return XP_TRUE;
} /* handleCommit */
@ -1371,15 +1371,14 @@ curses_util_turnChanged( XW_UtilCtxt* XP_UNUSED(uc), XP_S16 newTurn )
}
#endif
static XP_Bool
curses_util_warnIllegalWord( XW_UtilCtxt* XP_UNUSED(uc),
BadWordInfo* XP_UNUSED(bwi),
XP_U16 XP_UNUSED(player),
XP_Bool XP_UNUSED(turnLost) )
static void
curses_util_notifyIllegalWords( XW_UtilCtxt* XP_UNUSED(uc),
BadWordInfo* XP_UNUSED(bwi),
XP_U16 XP_UNUSED(player),
XP_Bool XP_UNUSED(turnLost) )
{
XP_WARNF( "curses_util_warnIllegalWord not implemented" );
return XP_FALSE;
} /* curses_util_warnIllegalWord */
XP_WARNF( "curses_util_notifyIllegalWords not implemented" );
} /* curses_util_notifyIllegalWord */
static void
curses_util_remSelected( XW_UtilCtxt* uc )
@ -1445,7 +1444,7 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
#ifdef XWFEATURE_TURNCHANGENOTIFY
util->vtable->m_util_turnChanged = curses_util_turnChanged;
#endif
util->vtable->m_util_warnIllegalWord = curses_util_warnIllegalWord;
util->vtable->m_util_notifyIllegalWords = curses_util_notifyIllegalWords;
util->vtable->m_util_remSelected = curses_util_remSelected;
#ifndef XWFEATURE_STANDALONE_ONLY
util->vtable->m_util_makeStreamFromAddr = curses_util_makeStreamFromAddr;

View file

@ -1445,7 +1445,7 @@ handle_trade_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
static void
handle_done_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
{
if ( board_commitTurn( globals->cGlobals.game.board, XP_FALSE ) ) {
if ( board_commitTurn( globals->cGlobals.game.board, XP_FALSE, XP_FALSE ) ) {
board_draw( globals->cGlobals.game.board );
disenable_buttons( globals );
}
@ -1543,7 +1543,7 @@ handle_hide_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
static void
handle_commit_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
{
if ( board_commitTurn( globals->cGlobals.game.board, XP_FALSE ) ) {
if ( board_commitTurn( globals->cGlobals.game.board, XP_FALSE, XP_FALSE ) ) {
board_draw( globals->cGlobals.game.board );
}
} /* handle_commit_button */
@ -2117,49 +2117,48 @@ gtk_util_requestTime( XW_UtilCtxt* uc )
globals->idleID = g_idle_add( idle_func, globals );
} /* gtk_util_requestTime */
static XP_Bool
gtk_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi, XP_U16 player,
XP_Bool turnLost )
static gint
ask_bad_words( gpointer data )
{
GtkGameGlobals* globals = (GtkGameGlobals*)data;
CommonGlobals* cGlobals = &globals->cGlobals;
if ( GTK_RESPONSE_YES == gtkask( globals->window, cGlobals->question,
GTK_BUTTONS_YES_NO, NULL ) ) {
board_commitTurn( cGlobals->game.board, XP_TRUE, XP_FALSE );
}
return 0;
}
static void
gtk_util_notifyIllegalWords( XW_UtilCtxt* uc, BadWordInfo* bwi, XP_U16 player,
XP_Bool turnLost )
{
XP_Bool result;
GtkGameGlobals* globals = (GtkGameGlobals*)uc->closure;
CommonGlobals* cGlobals = &globals->cGlobals;
char buf[300];
gchar* strs = g_strjoinv( "\", \"", (gchar**)bwi->words );
if ( turnLost ) {
char wordsBuf[256];
XP_U16 i;
XP_UCHAR* name = globals->cGlobals.gi->players[player].name;
XP_UCHAR* name = cGlobals->gi->players[player].name;
XP_ASSERT( !!name );
for ( i = 0, wordsBuf[0] = '\0'; ; ) {
char wordBuf[18];
sprintf( wordBuf, "\"%s\"", bwi->words[i] );
strcat( wordsBuf, wordBuf );
if ( ++i == bwi->nWords ) {
break;
}
strcat( wordsBuf, ", " );
}
sprintf( buf, "Player %d (%s) played illegal word[s] %s; loses turn.",
player+1, name, wordsBuf );
player+1, name, strs );
if ( globals->cGlobals.params->skipWarnings ) {
if ( cGlobals->params->skipWarnings ) {
XP_LOGF( "%s", buf );
} else {
gtkUserError( globals, buf );
}
result = XP_TRUE;
} else {
XP_ASSERT( bwi->nWords == 1 );
sprintf( buf, "Word \"%s\" not in the current dictionary (%s). "
"Use it anyway?", bwi->words[0], bwi->dictName );
result = GTK_RESPONSE_YES == gtkask( globals->window, buf,
GTK_BUTTONS_YES_NO, NULL );
}
sprintf( cGlobals->question, "Word[s] \"%s\" not in the current dictionary (%s). "
"Use anyway?", strs, bwi->dictName );
return result;
} /* gtk_util_warnIllegalWord */
(void)g_idle_add( ask_bad_words, globals );
}
g_free( strs );
} /* gtk_util_notifyIllegalWords */
static void
gtk_util_remSelected( XW_UtilCtxt* uc )
@ -2276,7 +2275,7 @@ ask_move( gpointer data )
gint chosen = gtkask( globals->window, cGlobals->question, buttons, NULL );
if ( GTK_RESPONSE_OK == chosen || chosen == GTK_RESPONSE_YES ) {
BoardCtxt* board = cGlobals->game.board;
if ( board_commitTurn( board, XP_TRUE ) ) {
if ( board_commitTurn( board, XP_TRUE, XP_TRUE ) ) {
board_draw( board );
}
}
@ -2315,7 +2314,7 @@ ask_trade( gpointer data )
cGlobals->question,
GTK_BUTTONS_YES_NO, NULL ) ) {
BoardCtxt* board = cGlobals->game.board;
if ( board_commitTurn( board, XP_TRUE ) ) {
if ( board_commitTurn( board, XP_TRUE, XP_TRUE ) ) {
board_draw( board );
}
}
@ -2488,7 +2487,7 @@ setupGtkUtilCallbacks( GtkGameGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_setTimer = gtk_util_setTimer;
util->vtable->m_util_clearTimer = gtk_util_clearTimer;
util->vtable->m_util_requestTime = gtk_util_requestTime;
util->vtable->m_util_warnIllegalWord = gtk_util_warnIllegalWord;
util->vtable->m_util_notifyIllegalWords = gtk_util_notifyIllegalWords;
util->vtable->m_util_remSelected = gtk_util_remSelected;
#ifndef XWFEATURE_STANDALONE_ONLY
util->vtable->m_util_makeStreamFromAddr = gtk_util_makeStreamFromAddr;