From 18fc21bfe47cf80d294fffc22eb00d7f4384cd62 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Sun, 27 Sep 2009 10:24:47 -0700 Subject: [PATCH 1/1] added a chat window to keep track of multiple conversations The chat-window patch affects: winboard.c, backend.c, winboard.rc, resource.h, backend.h, and adds the file winboard/wchat.c, which also affects makefile.gcc and makefile.ms. In addition I added a new option -keepAlive, which affects common.h (in addition to winboard.c and backend.c). As I had to modify backend.h, I also defined the -reset option type there, which we are going to add later. This required some changes to suppress warnings in wsettings.c. --- backend.c | 48 +++++++++- backend.h | 4 +- common.h | 6 + winboard/makefile.gcc | 9 +- winboard/makefile.ms | 9 +- winboard/resource.h | 8 ++ winboard/wchat.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++ winboard/winboard.c | 23 ++++- winboard/winboard.rc | 19 ++++ winboard/wsettings.c | 3 + 10 files changed, 372 insertions(+), 12 deletions(-) create mode 100644 winboard/wchat.c diff --git a/backend.c b/backend.c index 2f839b9..94d0e81 100644 --- a/backend.c +++ b/backend.c @@ -242,6 +242,9 @@ VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */ int lastIndex = 0; /* [HGM] autoinc: last game/position used in match mode */ int opponentKibitzes; int lastSavedGame; /* [HGM] save: ID of game */ +char chatPartner[MAX_CHAT][MSG_SIZ]; /* [HGM] chat: list of chatting partners */ +extern int chatCount; +int chattingPartner; /* States for ics_getting_history */ #define H_FALSE 0 @@ -1452,6 +1455,13 @@ read_from_player(isr, closure, message, count, error) } void +KeepAlive() +{ // [HGM] alive: periodically send dummy (date) command to ICS to prevent time-out + SendToICS("date\n"); + if(appData.keepAlive) ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000); +} + +void SendToICS(s) char *s; { @@ -2082,6 +2092,7 @@ read_from_ics(isr, closure, data, count, error) int tkind; int backup; /* [DM] For zippy color lines */ char *p; + char talker[MSG_SIZ]; // [HGM] chat if (appData.debugMode) { if (!error) { @@ -2262,6 +2273,12 @@ read_from_ics(isr, closure, data, count, error) parse[parse_pos++] = buf[i]; if (buf[i] == '\n') { parse[parse_pos] = NULLCHAR; + if(chattingPartner>=0) { + char mess[MSG_SIZ]; + sprintf(mess, "%s%s", talker, parse); + OutputChatMessage(chattingPartner, mess); + chattingPartner = -1; + } else if(!suppressKibitz) // [HGM] kibitz AppendComment(forwardMostMove, StripHighlight(parse)); else { // [HGM kibitz: divert memorized engine kibitz to engine-output window @@ -2398,6 +2415,32 @@ read_from_ics(isr, closure, data, count, error) } } // [HGM] kibitz: end of patch +//if(appData.debugMode) fprintf(debugFP, "hunt for tell, buf = %s\n", buf+i); + + // [HGM] chat: intercept tells by users for which we have an open chat window + if(started == STARTED_NONE && (looking_at(buf, &i, "* tells you:") || looking_at(buf, &i, "* says:") || + looking_at(buf, &i, "* whispers:"))) { + int p; + sscanf(star_match[0], "%[^(]", talker+1); // strip (C) or (U) off ICS handle + chattingPartner = -1; + if(buf[i-3] == 'r') // whisper; look if there is a WHISPER chatbox + for(p=0; p /* required for all Windows applications */ +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" + +#include "wsnap.h" + +int chatCount; +extern char chatPartner[MAX_CHAT][MSG_SIZ]; +HANDLE chatHandle[MAX_CHAT]; + +void SendToICS P((char *s)); +void ChatPopUp(); +void ChatPopDown(); + +/* Imports from backend.c */ +char * SavePart(char *str); +extern int opponentKibitzes; + +/* Imports from winboard.c */ +extern HWND ChatDialog; + +extern HINSTANCE hInst; +extern HWND hwndMain; + +extern WindowPlacement wpChat[MAX_CHAT]; + +extern BoardSize boardSize; + +/* Module variables */ +#define H_MARGIN 5 +#define V_MARGIN 5 + +// front end, although we might make GetWindowRect front end instead +static int GetControlWidth( HWND hDlg, int id ) +{ + RECT rc; + + GetWindowRect( GetDlgItem( hDlg, id ), &rc ); + + return rc.right - rc.left; +} + +// front end? +static int GetControlHeight( HWND hDlg, int id ) +{ + RECT rc; + + GetWindowRect( GetDlgItem( hDlg, id ), &rc ); + + return rc.bottom - rc.top; +} + +static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height ) +{ + HWND hControl = GetDlgItem( hDlg, id ); + + SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER ); +} + +// Also here some of the size calculations should go to the back end, and their actual application to a front-end routine +static void ResizeWindowControls( HWND hDlg ) +{ + RECT rc; + int clientWidth; + int clientHeight; + int maxControlWidth; + int buttonWidth, buttonHeight; +#if 0 +} +#else + /* Initialize variables */ + GetClientRect( hDlg, &rc ); + + clientWidth = rc.right - rc.left; + clientHeight = rc.bottom - rc.top; + + maxControlWidth = clientWidth - 2*H_MARGIN; + buttonWidth = GetControlWidth(hDlg, IDC_Send); + buttonHeight = GetControlHeight(hDlg, IDC_Send); + + /* Resize controls */ + SetControlPos( hDlg, IDC_Clear, maxControlWidth+H_MARGIN-2*buttonWidth-5, V_MARGIN, buttonWidth, buttonHeight ); + SetControlPos( hDlg, IDC_Send, maxControlWidth+H_MARGIN-buttonWidth, V_MARGIN, buttonWidth, buttonHeight ); + SetControlPos( hDlg, IDC_ChatMemo, H_MARGIN, 2*V_MARGIN+buttonHeight, maxControlWidth, clientHeight-3*V_MARGIN-2*buttonHeight ); + SetControlPos( hDlg, OPT_ChatInput, H_MARGIN, clientHeight-V_MARGIN-buttonHeight, maxControlWidth, buttonHeight ); + +// InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE ); +// InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE ); +} +#endif + +// front end. Actual printing of PV lines into the output field +static void InsertIntoMemo( HANDLE hDlg, char * text ) +{ + HANDLE hMemo = GetDlgItem(hDlg, IDC_ChatMemo); + + SendMessage( hMemo, EM_SETSEL, 1000000, 1000000 ); + + SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text ); + SendMessage( hMemo, EM_SCROLLCARET, 0, 0); +} + +// This seems pure front end +LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + static SnapData sd; + char buf[MSG_SIZ], mess[MSG_SIZ]; + int partner = -1, i; + + for(i=0; i %s\n", mess); // echo only tells, not whispers + InsertIntoMemo(hDlg, buf); + sprintf(buf, "tell %s %s\n", chatPartner[partner], mess); + } else sprintf(buf, "whisper %s\n", mess); // SAY box uses "say" to send + SendToICS(buf); + break; + + default: + break; + } + + break; + + case WM_CLOSE: + chatHandle[partner] = 0; + chatPartner[partner][0] = 0; + ChatPopDown(); + EndDialog(hDlg, TRUE); + break; + + case WM_SIZE: + ResizeWindowControls( hDlg ); + break; + + case WM_ENTERSIZEMOVE: + return OnEnterSizeMove( &sd, hDlg, wParam, lParam ); + + case WM_SIZING: + return OnSizing( &sd, hDlg, wParam, lParam ); + + case WM_MOVING: + return OnMoving( &sd, hDlg, wParam, lParam ); + + case WM_EXITSIZEMOVE: + return OnExitSizeMove( &sd, hDlg, wParam, lParam ); + } + + return FALSE; +} + +// front end +void ChatPopUp() +{ + FARPROC lpProc; + + if(chatCount >= MAX_CHAT) return; + + CheckMenuItem(GetMenu(hwndMain), IDM_NewChat, MF_CHECKED); + chatCount++; + + lpProc = MakeProcInstance( (FARPROC) ChatProc, hInst ); + + /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */ + CreateDialog( hInst, MAKEINTRESOURCE(DLG_Chat), hwndMain, (DLGPROC)lpProc ); + + FreeProcInstance(lpProc); + +} + +// front end +void ChatPopDown() +{ + if(--chatCount <= 0) + CheckMenuItem(GetMenu(hwndMain), IDM_NewChat, MF_UNCHECKED); +} + + +//------------------------ pure back-end routines ------------------------------- + +void OutputChatMessage(int partner, char *text) +{ + if(!chatHandle[partner]) return; + + InsertIntoMemo(chatHandle[partner], text); +} diff --git a/winboard/winboard.c b/winboard/winboard.c index d6f4a45..4cb6ef4 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -100,6 +100,8 @@ extern int whiteFlag, blackFlag; Boolean flipClock = FALSE; +extern HANDLE chatHandle[]; +extern int ics_type; void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber); VOID NewVariantPopup(HWND hwnd); @@ -108,6 +110,7 @@ int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames); void DisplayMove P((int moveNumber)); Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen)); +void ChatPopUp P(()); typedef struct { ChessSquare piece; POINT pos; /* window coordinates of current pos */ @@ -572,7 +575,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, if(msg.hwnd == e2) currentElement = 3; else if(msg.hwnd == moveHistoryDialog) currentElement = 4; else if(msg.hwnd == mh) currentElement = 4; else - if(msg.hwnd == evalGraphDialog) currentElement = 7; else + if(msg.hwnd == evalGraphDialog) currentElement = 6; else if(msg.hwnd == hText) currentElement = 5; else if(msg.hwnd == hInput) currentElement = 6; else for (i = 0; i < N_BUTTONS; i++) { @@ -597,7 +600,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, case 4: if(!MoveHistoryIsUp()) continue; h = mh; break; -// case 5: // input to eval graph does not seem to get here! +// case 6: // input to eval graph does not seem to get here! // if(!EvalGraphIsUp()) continue; // h = evalGraphDialog; break; case 5: @@ -629,6 +632,12 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) && !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) { + int done = 0, i; // [HGM] chat: dispatch cat-box messages + for(i=0; i