diff --git a/xwords4/wince/cedraw.c b/xwords4/wince/cedraw.c index 23fd73f9c..194c6b380 100755 --- a/xwords4/wince/cedraw.c +++ b/xwords4/wince/cedraw.c @@ -1904,6 +1904,19 @@ ce_draw_focus( CEDrawCtx* dctx, const RECT* invalR ) drawColoredRect( dctx, invalR, CE_FOCUS_COLOR ); } +void +ce_draw_status( CEDrawCtx* dctx, const RECT* rect, wchar_t stateCh ) +{ + CEAppGlobals* globals = dctx->globals; + + FillRect( globals->hdc, rect, dctx->brushes[CE_BKG_COLOR] ); + + DrawText( globals->hdc, &stateCh, 1, (RECT*)rect, + dctx->scoreIsVertical? + DT_CENTER | DT_BOTTOM : + DT_VCENTER | DT_RIGHT ); +} + #ifndef _WIN32_WCE HBRUSH ce_draw_getFocusBrush( const CEDrawCtx* dctx ) diff --git a/xwords4/wince/cedraw.h b/xwords4/wince/cedraw.h index 99b9e38ab..170108b22 100644 --- a/xwords4/wince/cedraw.h +++ b/xwords4/wince/cedraw.h @@ -28,6 +28,8 @@ CEDrawCtx* ce_drawctxt_make( MPFORMAL HWND mainWin, CEAppGlobals* globals ); void ce_draw_update( CEDrawCtx* dctx ); void ce_draw_erase( CEDrawCtx* dctx, const RECT* invalR ); void ce_draw_focus( CEDrawCtx* dctx, const RECT* invalR ); +void ce_draw_status( CEDrawCtx* dctx, const RECT* invalR, wchar_t stateCh ); + #ifndef _WIN32_WCE HBRUSH ce_draw_getFocusBrush( const CEDrawCtx* dctx ); #endif diff --git a/xwords4/wince/cemain.c b/xwords4/wince/cemain.c index 529467a0f..bd74a6dd0 100755 --- a/xwords4/wince/cemain.c +++ b/xwords4/wince/cemain.c @@ -81,6 +81,9 @@ typedef struct FileWriteState { static XP_S16 ce_send_proc( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr, void* closure ); +static void ce_relay_status( void* closure, + CommsRelayState newState ); + # ifdef COMMS_HEARTBEAT static void ce_reset_proc( void* closure ); # endif @@ -524,6 +527,9 @@ typedef struct CEBoardParms { XP_U16 trayWidth; XP_U16 timerLeft, timerTop, timerWidth, timerHeight; +#ifndef XWFEATURE_STANDALONE_ONLY + XP_U16 netstatLeft, netstatTop, netstatWidth, netstatHeight; +#endif XP_U16 boardLeft, trayLeft; XP_U16 scoreWidth; @@ -638,6 +644,26 @@ figureBoardParms( CEAppGlobals* globals, const XP_U16 nRows, } /* XP_LOGF( "hScale=%d; vScale=%d; trayHeight=%d", hScale, vScale, trayHeight ); */ +#ifndef XWFEATURE_STANDALONE_ONLY + if ( !!globals->game.comms ) { + /* If we're horizontal, steal from the right of the scoreboard. If + vertical, from the bottom. */ + if ( horiz ) { + bparms->netstatWidth = hScale; + scoreWidth -= bparms->netstatWidth; + bparms->netstatLeft = scoreWidth; + bparms->netstatTop = 0; + bparms->netstatHeight = scoreHeight; + } else { + bparms->netstatLeft = 0; + bparms->netstatHeight = vScale; + scoreHeight -= bparms->netstatHeight; + bparms->netstatTop = scoreHeight; + bparms->netstatWidth = scoreWidth; + } + } +#endif + if ( globals->gameInfo.timerEnabled ) { if ( horiz ) { bparms->timerWidth = scoreWidth / 6; /* arbitrarily, one sixth */ @@ -749,6 +775,17 @@ cePositionBoard( CEAppGlobals* globals ) figureBoardParms( globals, nCols, &bparms ); setOwnedRects( globals, nCols, &bparms ); +#ifndef XWFEATURE_STANDALONE_ONLY + if ( !!globals->game.comms ) { + globals->relayStatusR.left = bparms.adjLeft + bparms.netstatLeft; + globals->relayStatusR.top = bparms.adjTop + bparms.netstatTop; + globals->relayStatusR.right = globals->relayStatusR.left + + bparms.netstatWidth; + globals->relayStatusR.bottom = globals->relayStatusR.top + + bparms.netstatHeight; + } +#endif + if ( globals->gameInfo.timerEnabled ) { board_setTimerLoc( globals->game.board, bparms.adjLeft + bparms.timerLeft, @@ -825,6 +862,7 @@ ceInitTProcs( CEAppGlobals* globals, TransportProcs* procs ) #ifdef COMMS_HEARTBEAT procs->reset = ce_reset_proc; #endif + procs->rstatus = ce_relay_status; procs->closure = globals; } @@ -1590,6 +1628,34 @@ ceDoHistory( CEAppGlobals* globals ) MB_OK | MB_ICONINFORMATION, XP_TRUE ); } /* ceDoHistory */ +static wchar_t +ceStateChar( const CEAppGlobals* globals ) +{ + /* Idea is to give user a clue how the network connection's coming. + Relay only matters if we have a socket open. So use that first. */ + CommsRelayState relayState = globals->relayState; + CeConnState socketState = globals->socketState; + wchar_t ch; + + if ( socketState == CE_IPST_CONNECTED ) { + switch( relayState ) { + case COMMS_RELAYSTATE_UNCONNECTED: ch = L'x'; break; + case COMMS_RELAYSTATE_CONNECT_PENDING: ch = L'c'; break; + case COMMS_RELAYSTATE_CONNECTED: ch = L'C'; break; + case COMMS_RELAYSTATE_ALLCONNECTED: ch = L'A'; break; + } + } else { + switch( socketState ) { + case CE_IPST_START: + case CE_IPST_RESOLVINGHOST: ch = L'4'; break; + case CE_IPST_HOSTRESOLVED: ch = L'3'; break; + case CE_IPST_CONNECTING: ch = L'2'; break; + case CE_IPST_CONNECTED: ch = L'1'; break; + } + } + return ch; +} + static void drawInsidePaint( CEAppGlobals* globals, const RECT* invalR ) { @@ -1612,6 +1678,14 @@ drawInsidePaint( CEAppGlobals* globals, const RECT* invalR ) ce_draw_erase( globals->draw, &interR ); } } + +#ifndef XWFEATURE_STANDALONE_ONLY + if ( IntersectRect( &interR, invalR, &globals->relayStatusR ) ) { + wchar_t ch = ceStateChar( globals ); + ce_draw_status( globals->draw, &globals->relayStatusR, ch ); + } +#endif + #ifdef _WIN32_WCE for ( ii = 0; ii < VSIZE(globals->scrollRects); ++ii ) { if ( IntersectRect( &interR, invalR, @@ -2950,6 +3024,14 @@ got_data_proc( XP_U8* data, XP_U16 len, void* closure ) return draw; } /* got_data_proc */ + +static void +sock_state_change( void* closure, CeConnState state ) +{ + CEAppGlobals* globals = (CEAppGlobals*)closure; + globals->socketState = state; + InvalidateRect( globals->hWnd, &globals->relayStatusR, TRUE /* erase */ ); +} #endif #ifdef COMMS_HEARTBEAT @@ -2961,6 +3043,14 @@ ce_reset_proc( void* XP_UNUSED_STANDALONE(closure) ) #endif #ifndef XWFEATURE_STANDALONE_ONLY +static void +ce_relay_status( void* closure, CommsRelayState newState ) +{ + CEAppGlobals* globals = (CEAppGlobals*)closure; + globals->relayState = newState; + InvalidateRect( globals->hWnd, &globals->relayStatusR, TRUE /* erase */ ); +} + static XP_S16 ce_send_proc( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addrp, void* closure ) @@ -2983,7 +3073,9 @@ ce_send_proc( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addrp, case COMMS_CONN_RELAY: if ( !globals->socketWrap ) { globals->socketWrap = ce_sockwrap_new( MPPARM(globals->mpool) - got_data_proc, globals ); + globals->hWnd, + got_data_proc, + sock_state_change, globals ); } nSent = ce_sockwrap_send( globals->socketWrap, buf, len, addrp ); diff --git a/xwords4/wince/cemain.h b/xwords4/wince/cemain.h index 7a2798512..0a747ee31 100755 --- a/xwords4/wince/cemain.h +++ b/xwords4/wince/cemain.h @@ -27,6 +27,7 @@ #include "game.h" #include "util.h" #include "mempool.h" +#include "cesockwr.h" #define LCROSSWORDS_DIR_NODBG L"Crosswords" #define CE_GAMEFILE_VERSION1 0x01 /* means draw gets to save/restore */ @@ -168,6 +169,12 @@ typedef struct _CEAppGlobals { XP_Bool hintPending; XP_Bool doGlobalPrefs; +#ifndef XWFEATURE_STANDALONE_ONLY + CommsRelayState relayState; + CeConnState socketState; + RECT relayStatusR; +#endif + #ifndef _WIN32_WCE XP_U16 dbWidth, dbHeight; #endif diff --git a/xwords4/wince/cesockwr.c b/xwords4/wince/cesockwr.c index 1c7cf9755..17156c579 100755 --- a/xwords4/wince/cesockwr.c +++ b/xwords4/wince/cesockwr.c @@ -1,4 +1,4 @@ -/* -*- compile-command: "make -j TARGET_OS=win32 DEBUG=TRUE" -*- */ +/* -*- compile-command: "make -j2 TARGET_OS=win32 DEBUG=TRUE" -*- */ /* * Copyright 2005-2009 by Eric House (xwords@eehouse.org). All rights * reserved. @@ -42,19 +42,13 @@ enum { WRITER_THREAD, READER_THREAD, N_THREADS }; -typedef enum { - CE_IPST_START - ,CE_IPST_RESOLVINGHOST - ,CE_IPST_HOSTRESOLVED - ,CE_IPST_CONNECTING - ,CE_IPST_CONNECTED -} CeConnState; - #define MAX_QUEUE_SIZE 6 struct CeSocketWrapper { + HWND hWnd; DataRecvProc dataProc; - CEAppGlobals* globals; + StateChangeProc stateProc; + void* closure; union { HOSTENT hent; @@ -160,6 +154,8 @@ stateChanged( CeSocketWrapper* self, CeConnState newState ) XP_LOGF( "%s: %s -> %s", __func__, ConnState2Str( curState ), ConnState2Str( newState ) ); + (*self->stateProc)( self->closure, newState ); + switch( newState ) { case CE_IPST_START: break; @@ -174,8 +170,7 @@ stateChanged( CeSocketWrapper* self, CeConnState newState ) send_packet_if( self ); break; } - -} +} /* stateChanged */ static XP_Bool connectSocket( CeSocketWrapper* self ) @@ -191,7 +186,7 @@ connectSocket( CeSocketWrapper* self ) struct sockaddr_in name = {0}; /* Put socket in non-blocking mode */ - if ( 0 != WSAAsyncSelect( sock, self->globals->hWnd, + if ( 0 != WSAAsyncSelect( sock, self->hWnd, XWWM_SOCKET_EVT, FD_READ | FD_WRITE | FD_CONNECT ) ) { XP_WARNF( "WSAAsyncSelect failed" ); @@ -256,7 +251,7 @@ getHostAddr( CeSocketWrapper* self ) XP_LOGF( "%s: calling WSAAsyncGetHostByName(%s)", __func__, self->addrRec.u.ip_relay.hostName ); self->getHostTask - = WSAAsyncGetHostByName( self->globals->hWnd, + = WSAAsyncGetHostByName( self->hWnd, XWWM_HOSTNAME_ARRIVED, self->addrRec.u.ip_relay.hostName, (char*)&self->hostNameUnion, @@ -271,15 +266,18 @@ getHostAddr( CeSocketWrapper* self ) } CeSocketWrapper* -ce_sockwrap_new( MPFORMAL DataRecvProc proc, CEAppGlobals* globals ) +ce_sockwrap_new( MPFORMAL HWND hWnd, DataRecvProc dataCB, + StateChangeProc stateCB, void* closure ) { CeSocketWrapper* self = NULL; self = XP_MALLOC( mpool, sizeof(*self) ); XP_MEMSET( self, 0, sizeof(*self) ); - self->dataProc = proc; - self->globals = globals; + self->hWnd = hWnd; + self->dataProc = dataCB; + self->stateProc = stateCB; + self->closure = closure; MPASSIGN(self->mpool, mpool ); self->socket = -1; @@ -368,7 +366,7 @@ dispatch_msgs( CeSocketWrapper* self ) /* first send */ XP_LOGF( "%s: sending %d bytes to dataProc", __func__, msgLen ); draw = (*self->dataProc)( (XP_U8*)&self->in_buf[sizeof(msgLen)], - msgLen, self->globals ) + msgLen, self->closure ) || draw; /* then move down any additional bytes */ diff --git a/xwords4/wince/cesockwr.h b/xwords4/wince/cesockwr.h index 0fbf395f8..424258ce9 100755 --- a/xwords4/wince/cesockwr.h +++ b/xwords4/wince/cesockwr.h @@ -23,14 +23,22 @@ #include "comms.h" #include "mempool.h" -#include "cemain.h" + +typedef enum { + CE_IPST_START + ,CE_IPST_RESOLVINGHOST + ,CE_IPST_HOSTRESOLVED + ,CE_IPST_CONNECTING + ,CE_IPST_CONNECTED +} CeConnState; typedef struct CeSocketWrapper CeSocketWrapper; /* forward */ typedef XP_Bool (*DataRecvProc)( XP_U8* data, XP_U16 len, void* closure ); +typedef void (*StateChangeProc)( void* closure, CeConnState state ); - -CeSocketWrapper* ce_sockwrap_new( MPFORMAL DataRecvProc proc, - CEAppGlobals* globals ); +CeSocketWrapper* ce_sockwrap_new( MPFORMAL HWND hWnd, DataRecvProc dataCB, + StateChangeProc stateCB, + void* globals ); void ce_sockwrap_delete( CeSocketWrapper* self ); void ce_sockwrap_hostname( CeSocketWrapper* self, WPARAM wParam, LPARAM lParam );